bad commit
@ -1,76 +0,0 @@
|
|||||||
'''
|
|
||||||
3D Rotating Monkey Head
|
|
||||||
========================
|
|
||||||
|
|
||||||
This example demonstrates using OpenGL to display a rotating monkey head. This
|
|
||||||
includes loading a Blender OBJ file, shaders written in OpenGL's Shading
|
|
||||||
Language (GLSL), and using scheduled callbacks.
|
|
||||||
|
|
||||||
The monkey.obj file is an OBJ file output from the Blender free 3D creation
|
|
||||||
software. The file is text, listing vertices and faces and is loaded
|
|
||||||
using a class in the file objloader.py. The file simple.glsl is
|
|
||||||
a simple vertex and fragment shader written in GLSL.
|
|
||||||
'''
|
|
||||||
|
|
||||||
from kivy.app import App
|
|
||||||
from kivy.clock import Clock
|
|
||||||
from kivy.core.window import Window
|
|
||||||
from kivy.uix.widget import Widget
|
|
||||||
from kivy.resources import resource_find
|
|
||||||
from kivy.graphics.transformation import Matrix
|
|
||||||
from kivy.graphics.opengl import *
|
|
||||||
from kivy.graphics import *
|
|
||||||
from objloader import ObjFile
|
|
||||||
|
|
||||||
|
|
||||||
class Renderer(Widget):
|
|
||||||
def __init__(self, **kwargs):
|
|
||||||
self.canvas = RenderContext(compute_normal_mat=True)
|
|
||||||
self.canvas.shader.source = resource_find('simple.glsl')
|
|
||||||
self.scene = ObjFile(resource_find("monkey.obj"))
|
|
||||||
super(Renderer, self).__init__(**kwargs)
|
|
||||||
with self.canvas:
|
|
||||||
self.cb = Callback(self.setup_gl_context)
|
|
||||||
PushMatrix()
|
|
||||||
self.setup_scene()
|
|
||||||
PopMatrix()
|
|
||||||
self.cb = Callback(self.reset_gl_context)
|
|
||||||
Clock.schedule_interval(self.update_glsl, 1 / 60.)
|
|
||||||
|
|
||||||
def setup_gl_context(self, *args):
|
|
||||||
glEnable(GL_DEPTH_TEST)
|
|
||||||
|
|
||||||
def reset_gl_context(self, *args):
|
|
||||||
glDisable(GL_DEPTH_TEST)
|
|
||||||
|
|
||||||
def update_glsl(self, delta):
|
|
||||||
asp = self.width / float(self.height)
|
|
||||||
proj = Matrix().view_clip(-asp, asp, -1, 1, 1, 100, 1)
|
|
||||||
self.canvas['projection_mat'] = proj
|
|
||||||
self.canvas['diffuse_light'] = (1.0, 1.0, 0.8)
|
|
||||||
self.canvas['ambient_light'] = (0.1, 0.1, 0.1)
|
|
||||||
self.rot.angle += delta * 100
|
|
||||||
|
|
||||||
def setup_scene(self):
|
|
||||||
Color(1, 1, 1, 1)
|
|
||||||
PushMatrix()
|
|
||||||
Translate(0, 0, -3)
|
|
||||||
self.rot = Rotate(1, 0, 1, 0)
|
|
||||||
m = list(self.scene.objects.values())[0]
|
|
||||||
UpdateNormalMatrix()
|
|
||||||
self.mesh = Mesh(
|
|
||||||
vertices=m.vertices,
|
|
||||||
indices=m.indices,
|
|
||||||
fmt=m.vertex_format,
|
|
||||||
mode='triangles',
|
|
||||||
)
|
|
||||||
PopMatrix()
|
|
||||||
|
|
||||||
|
|
||||||
class RendererApp(App):
|
|
||||||
def build(self):
|
|
||||||
return Renderer()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
RendererApp().run()
|
|
@ -1,147 +0,0 @@
|
|||||||
class MeshData(object):
|
|
||||||
def __init__(self, **kwargs):
|
|
||||||
self.name = kwargs.get("name")
|
|
||||||
self.vertex_format = [
|
|
||||||
(b'v_pos', 3, 'float'),
|
|
||||||
(b'v_normal', 3, 'float'),
|
|
||||||
(b'v_tc0', 2, 'float')]
|
|
||||||
self.vertices = []
|
|
||||||
self.indices = []
|
|
||||||
|
|
||||||
def calculate_normals(self):
|
|
||||||
for i in range(len(self.indices) / (3)):
|
|
||||||
fi = i * 3
|
|
||||||
v1i = self.indices[fi]
|
|
||||||
v2i = self.indices[fi + 1]
|
|
||||||
v3i = self.indices[fi + 2]
|
|
||||||
|
|
||||||
vs = self.vertices
|
|
||||||
p1 = [vs[v1i + c] for c in range(3)]
|
|
||||||
p2 = [vs[v2i + c] for c in range(3)]
|
|
||||||
p3 = [vs[v3i + c] for c in range(3)]
|
|
||||||
|
|
||||||
u, v = [0, 0, 0], [0, 0, 0]
|
|
||||||
for j in range(3):
|
|
||||||
v[j] = p2[j] - p1[j]
|
|
||||||
u[j] = p3[j] - p1[j]
|
|
||||||
|
|
||||||
n = [0, 0, 0]
|
|
||||||
n[0] = u[1] * v[2] - u[2] * v[1]
|
|
||||||
n[1] = u[2] * v[0] - u[0] * v[2]
|
|
||||||
n[2] = u[0] * v[1] - u[1] * v[0]
|
|
||||||
|
|
||||||
for k in range(3):
|
|
||||||
self.vertices[v1i + 3 + k] = n[k]
|
|
||||||
self.vertices[v2i + 3 + k] = n[k]
|
|
||||||
self.vertices[v3i + 3 + k] = n[k]
|
|
||||||
|
|
||||||
|
|
||||||
class ObjFile:
|
|
||||||
def finish_object(self):
|
|
||||||
if self._current_object is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
mesh = MeshData()
|
|
||||||
idx = 0
|
|
||||||
for f in self.faces:
|
|
||||||
verts = f[0]
|
|
||||||
norms = f[1]
|
|
||||||
tcs = f[2]
|
|
||||||
for i in range(3):
|
|
||||||
# get normal components
|
|
||||||
n = (0.0, 0.0, 0.0)
|
|
||||||
if norms[i] != -1:
|
|
||||||
n = self.normals[norms[i] - 1]
|
|
||||||
|
|
||||||
# get texture coordinate components
|
|
||||||
t = (0.0, 0.0)
|
|
||||||
if tcs[i] != -1:
|
|
||||||
t = self.texcoords[tcs[i] - 1]
|
|
||||||
|
|
||||||
# get vertex components
|
|
||||||
v = self.vertices[verts[i] - 1]
|
|
||||||
|
|
||||||
data = [v[0], v[1], v[2], n[0], n[1], n[2], t[0], t[1]]
|
|
||||||
mesh.vertices.extend(data)
|
|
||||||
|
|
||||||
tri = [idx, idx + 1, idx + 2]
|
|
||||||
mesh.indices.extend(tri)
|
|
||||||
idx += 3
|
|
||||||
|
|
||||||
self.objects[self._current_object] = mesh
|
|
||||||
# mesh.calculate_normals()
|
|
||||||
self.faces = []
|
|
||||||
|
|
||||||
def __init__(self, filename, swapyz=False):
|
|
||||||
"""Loads a Wavefront OBJ file. """
|
|
||||||
self.objects = {}
|
|
||||||
self.vertices = []
|
|
||||||
self.normals = []
|
|
||||||
self.texcoords = []
|
|
||||||
self.faces = []
|
|
||||||
|
|
||||||
self._current_object = None
|
|
||||||
|
|
||||||
material = None
|
|
||||||
for line in open(filename, "r"):
|
|
||||||
if line.startswith('#'):
|
|
||||||
continue
|
|
||||||
if line.startswith('s'):
|
|
||||||
continue
|
|
||||||
values = line.split()
|
|
||||||
if not values:
|
|
||||||
continue
|
|
||||||
if values[0] == 'o':
|
|
||||||
self.finish_object()
|
|
||||||
self._current_object = values[1]
|
|
||||||
# elif values[0] == 'mtllib':
|
|
||||||
# self.mtl = MTL(values[1])
|
|
||||||
# elif values[0] in ('usemtl', 'usemat'):
|
|
||||||
# material = values[1]
|
|
||||||
if values[0] == 'v':
|
|
||||||
v = list(map(float, values[1:4]))
|
|
||||||
if swapyz:
|
|
||||||
v = v[0], v[2], v[1]
|
|
||||||
self.vertices.append(v)
|
|
||||||
elif values[0] == 'vn':
|
|
||||||
v = list(map(float, values[1:4]))
|
|
||||||
if swapyz:
|
|
||||||
v = v[0], v[2], v[1]
|
|
||||||
self.normals.append(v)
|
|
||||||
elif values[0] == 'vt':
|
|
||||||
self.texcoords.append(map(float, values[1:3]))
|
|
||||||
elif values[0] == 'f':
|
|
||||||
face = []
|
|
||||||
texcoords = []
|
|
||||||
norms = []
|
|
||||||
for v in values[1:]:
|
|
||||||
w = v.split('/')
|
|
||||||
face.append(int(w[0]))
|
|
||||||
if len(w) >= 2 and len(w[1]) > 0:
|
|
||||||
texcoords.append(int(w[1]))
|
|
||||||
else:
|
|
||||||
texcoords.append(-1)
|
|
||||||
if len(w) >= 3 and len(w[2]) > 0:
|
|
||||||
norms.append(int(w[2]))
|
|
||||||
else:
|
|
||||||
norms.append(-1)
|
|
||||||
self.faces.append((face, norms, texcoords, material))
|
|
||||||
self.finish_object()
|
|
||||||
|
|
||||||
|
|
||||||
def MTL(filename):
|
|
||||||
contents = {}
|
|
||||||
mtl = None
|
|
||||||
return
|
|
||||||
for line in open(filename, "r"):
|
|
||||||
if line.startswith('#'):
|
|
||||||
continue
|
|
||||||
values = line.split()
|
|
||||||
if not values:
|
|
||||||
continue
|
|
||||||
if values[0] == 'newmtl':
|
|
||||||
mtl = contents[values[1]] = {}
|
|
||||||
elif mtl is None:
|
|
||||||
raise ValueError("mtl file doesn't start with newmtl stmt")
|
|
||||||
mtl[values[0]] = values[1:]
|
|
||||||
return contents
|
|
@ -1,47 +0,0 @@
|
|||||||
/* simple.glsl
|
|
||||||
|
|
||||||
simple diffuse lighting based on laberts cosine law; see e.g.:
|
|
||||||
http://en.wikipedia.org/wiki/Lambertian_reflectance
|
|
||||||
http://en.wikipedia.org/wiki/Lambert%27s_cosine_law
|
|
||||||
*/
|
|
||||||
---VERTEX SHADER-------------------------------------------------------
|
|
||||||
#ifdef GL_ES
|
|
||||||
precision highp float;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
attribute vec3 v_pos;
|
|
||||||
attribute vec3 v_normal;
|
|
||||||
|
|
||||||
uniform mat4 modelview_mat;
|
|
||||||
uniform mat4 projection_mat;
|
|
||||||
|
|
||||||
varying vec4 normal_vec;
|
|
||||||
varying vec4 vertex_pos;
|
|
||||||
|
|
||||||
void main (void) {
|
|
||||||
//compute vertex position in eye_space and normalize normal vector
|
|
||||||
vec4 pos = modelview_mat * vec4(v_pos,1.0);
|
|
||||||
vertex_pos = pos;
|
|
||||||
normal_vec = vec4(v_normal,0.0);
|
|
||||||
gl_Position = projection_mat * pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
---FRAGMENT SHADER-----------------------------------------------------
|
|
||||||
#ifdef GL_ES
|
|
||||||
precision highp float;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
varying vec4 normal_vec;
|
|
||||||
varying vec4 vertex_pos;
|
|
||||||
|
|
||||||
uniform mat4 normal_mat;
|
|
||||||
|
|
||||||
void main (void){
|
|
||||||
//correct normal, and compute light vector (assume light at the eye)
|
|
||||||
vec4 v_normal = normalize( normal_mat * normal_vec ) ;
|
|
||||||
vec4 v_light = normalize( vec4(0,0,0,1) - vertex_pos );
|
|
||||||
//reflectance based on lamberts law of cosine
|
|
||||||
float theta = clamp(dot(v_normal, v_light), 0.0, 1.0);
|
|
||||||
gl_FragColor = vec4(theta, theta, theta, 1.0);
|
|
||||||
}
|
|
@ -1,72 +0,0 @@
|
|||||||
#:kivy 1.1.0
|
|
||||||
|
|
||||||
Root:
|
|
||||||
text_input: text_input
|
|
||||||
|
|
||||||
BoxLayout:
|
|
||||||
orientation: 'vertical'
|
|
||||||
BoxLayout:
|
|
||||||
size_hint_y: None
|
|
||||||
height: 30
|
|
||||||
Button:
|
|
||||||
text: 'Load'
|
|
||||||
on_release: root.show_load()
|
|
||||||
Button:
|
|
||||||
text: 'Save'
|
|
||||||
on_release: root.show_save()
|
|
||||||
|
|
||||||
BoxLayout:
|
|
||||||
TextInput:
|
|
||||||
id: text_input
|
|
||||||
text: ''
|
|
||||||
|
|
||||||
RstDocument:
|
|
||||||
text: text_input.text
|
|
||||||
show_errors: True
|
|
||||||
|
|
||||||
<LoadDialog>:
|
|
||||||
BoxLayout:
|
|
||||||
size: root.size
|
|
||||||
pos: root.pos
|
|
||||||
orientation: "vertical"
|
|
||||||
FileChooserListView:
|
|
||||||
id: filechooser
|
|
||||||
|
|
||||||
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
|
|
||||||
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)
|
|
||||||
|
|
@ -1,64 +0,0 @@
|
|||||||
from kivy.app import App
|
|
||||||
from kivy.uix.floatlayout import FloatLayout
|
|
||||||
from kivy.factory import Factory
|
|
||||||
from kivy.properties import ObjectProperty
|
|
||||||
from kivy.uix.popup import Popup
|
|
||||||
|
|
||||||
import os
|
|
||||||
|
|
||||||
|
|
||||||
class LoadDialog(FloatLayout):
|
|
||||||
load = ObjectProperty(None)
|
|
||||||
cancel = ObjectProperty(None)
|
|
||||||
|
|
||||||
|
|
||||||
class SaveDialog(FloatLayout):
|
|
||||||
save = ObjectProperty(None)
|
|
||||||
text_input = ObjectProperty(None)
|
|
||||||
cancel = ObjectProperty(None)
|
|
||||||
|
|
||||||
|
|
||||||
class Root(FloatLayout):
|
|
||||||
loadfile = ObjectProperty(None)
|
|
||||||
savefile = ObjectProperty(None)
|
|
||||||
text_input = ObjectProperty(None)
|
|
||||||
|
|
||||||
def dismiss_popup(self):
|
|
||||||
self._popup.dismiss()
|
|
||||||
|
|
||||||
def show_load(self):
|
|
||||||
content = LoadDialog(load=self.load, cancel=self.dismiss_popup)
|
|
||||||
self._popup = Popup(title="Load file", content=content,
|
|
||||||
size_hint=(0.9, 0.9))
|
|
||||||
self._popup.open()
|
|
||||||
|
|
||||||
def show_save(self):
|
|
||||||
content = SaveDialog(save=self.save, cancel=self.dismiss_popup)
|
|
||||||
self._popup = Popup(title="Save file", content=content,
|
|
||||||
size_hint=(0.9, 0.9))
|
|
||||||
self._popup.open()
|
|
||||||
|
|
||||||
def load(self, path, filename):
|
|
||||||
with open(os.path.join(path, filename[0])) as stream:
|
|
||||||
self.text_input.text = stream.read()
|
|
||||||
|
|
||||||
self.dismiss_popup()
|
|
||||||
|
|
||||||
def save(self, path, filename):
|
|
||||||
with open(os.path.join(path, filename), 'w') as stream:
|
|
||||||
stream.write(self.text_input.text)
|
|
||||||
|
|
||||||
self.dismiss_popup()
|
|
||||||
|
|
||||||
|
|
||||||
class Editor(App):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
Factory.register('Root', cls=Root)
|
|
||||||
Factory.register('LoadDialog', cls=LoadDialog)
|
|
||||||
Factory.register('SaveDialog', cls=SaveDialog)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
Editor().run()
|
|
@ -1,3 +0,0 @@
|
|||||||
title=Compass
|
|
||||||
author=Nik Klever
|
|
||||||
orientation=portrait
|
|
@ -1,25 +0,0 @@
|
|||||||
#:kivy 1.7.0
|
|
||||||
|
|
||||||
FloatLayout:
|
|
||||||
|
|
||||||
canvas:
|
|
||||||
Color:
|
|
||||||
rgb: .98, .98, .98
|
|
||||||
Rectangle:
|
|
||||||
size: self.size
|
|
||||||
|
|
||||||
Image:
|
|
||||||
source: 'rose.png'
|
|
||||||
|
|
||||||
Image:
|
|
||||||
source: 'needle.png'
|
|
||||||
|
|
||||||
canvas.before:
|
|
||||||
PushMatrix
|
|
||||||
Rotate:
|
|
||||||
angle: app.needle_angle
|
|
||||||
axis: 0, 0, 1
|
|
||||||
origin: self.center
|
|
||||||
|
|
||||||
canvas.after:
|
|
||||||
PopMatrix
|
|
@ -1,77 +0,0 @@
|
|||||||
'''
|
|
||||||
Compass example
|
|
||||||
===============
|
|
||||||
|
|
||||||
This example is a demonstration of Hardware class usage.
|
|
||||||
But it has severals drawbacks, like using only the magnetic sensor, and
|
|
||||||
extrapolating values to get the orientation. The compass is absolutely not
|
|
||||||
accurate.
|
|
||||||
|
|
||||||
The right way would be to get the accelerometer + magnetic, and computer
|
|
||||||
everything according to the phone orientation. This is not the purpose of this
|
|
||||||
example right now.
|
|
||||||
|
|
||||||
You can compile it with::
|
|
||||||
|
|
||||||
./build.py --package org.test.compass --name compass \
|
|
||||||
--private ~/code/kivy/examples/android/compass \
|
|
||||||
--window --version 1.0 debug installd
|
|
||||||
'''
|
|
||||||
|
|
||||||
|
|
||||||
import kivy
|
|
||||||
kivy.require('1.7.0')
|
|
||||||
|
|
||||||
from jnius import autoclass
|
|
||||||
from math import floor
|
|
||||||
from kivy.app import App
|
|
||||||
from kivy.properties import NumericProperty
|
|
||||||
from kivy.clock import Clock
|
|
||||||
from kivy.vector import Vector
|
|
||||||
from kivy.animation import Animation
|
|
||||||
|
|
||||||
Hardware = autoclass('org.renpy.android.Hardware')
|
|
||||||
|
|
||||||
|
|
||||||
class CompassApp(App):
|
|
||||||
|
|
||||||
needle_angle = NumericProperty(0)
|
|
||||||
|
|
||||||
def build(self):
|
|
||||||
self._anim = None
|
|
||||||
Hardware.magneticFieldSensorEnable(True)
|
|
||||||
Clock.schedule_interval(self.update_compass, 1 / 10.)
|
|
||||||
|
|
||||||
def update_compass(self, *args):
|
|
||||||
# read the magnetic sensor from the Hardware class
|
|
||||||
(x, y, z) = Hardware.magneticFieldSensorReading()
|
|
||||||
|
|
||||||
# calculate the angle
|
|
||||||
needle_angle = Vector(x, y).angle((0, 1)) + 90.
|
|
||||||
|
|
||||||
# fix animation transition around the unit circle
|
|
||||||
if (self.needle_angle % 360) - needle_angle > 180:
|
|
||||||
needle_angle += 360
|
|
||||||
elif (self.needle_angle % 360) - needle_angle < -180:
|
|
||||||
needle_angle -= 360
|
|
||||||
# add the number of revolutions to the result
|
|
||||||
needle_angle += 360 * floor(self.needle_angle / 360.)
|
|
||||||
|
|
||||||
# animate the needle
|
|
||||||
if self._anim:
|
|
||||||
self._anim.stop(self)
|
|
||||||
self._anim = Animation(needle_angle=needle_angle, d=.2, t='out_quad')
|
|
||||||
self._anim.start(self)
|
|
||||||
|
|
||||||
def on_pause(self):
|
|
||||||
# when you are going on pause, don't forget to stop the sensor
|
|
||||||
Hardware.magneticFieldSensorEnable(False)
|
|
||||||
return True
|
|
||||||
|
|
||||||
def on_resume(self):
|
|
||||||
# reactivate the sensor when you are back to the app
|
|
||||||
Hardware.magneticFieldSensorEnable(True)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
CompassApp().run()
|
|
Before Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 31 KiB |
@ -1,3 +0,0 @@
|
|||||||
title=TakePicture
|
|
||||||
author=Mathieu Virbel
|
|
||||||
orientation=portrait
|
|
@ -1,80 +0,0 @@
|
|||||||
'''
|
|
||||||
Take picture
|
|
||||||
============
|
|
||||||
|
|
||||||
.. author:: Mathieu Virbel <mat@kivy.org>
|
|
||||||
|
|
||||||
Little example to demonstrate how to start an Intent, and get the result.
|
|
||||||
When you use the Android.startActivityForResult(), the result will be
|
|
||||||
dispatched into onActivityResult. You can catch the event with the
|
|
||||||
android.activity API from python-for-android project.
|
|
||||||
|
|
||||||
If you want to compile it, don't forget to add the CAMERA permission::
|
|
||||||
|
|
||||||
./build.py --name 'TakePicture' --package org.test.takepicture \
|
|
||||||
--permission CAMERA --version 1 \
|
|
||||||
--private ~/code/kivy/examples/android/takepicture \
|
|
||||||
debug installd
|
|
||||||
|
|
||||||
'''
|
|
||||||
|
|
||||||
__version__ = '0.1'
|
|
||||||
|
|
||||||
from kivy.app import App
|
|
||||||
from os.path import exists
|
|
||||||
from jnius import autoclass, cast
|
|
||||||
from android import activity, mActivity
|
|
||||||
from functools import partial
|
|
||||||
from kivy.clock import Clock
|
|
||||||
from kivy.uix.scatter import Scatter
|
|
||||||
from kivy.properties import StringProperty
|
|
||||||
|
|
||||||
from PIL import Image
|
|
||||||
|
|
||||||
Intent = autoclass('android.content.Intent')
|
|
||||||
MediaStore = autoclass('android.provider.MediaStore')
|
|
||||||
Uri = autoclass('android.net.Uri')
|
|
||||||
Environment = autoclass('android.os.Environment')
|
|
||||||
|
|
||||||
|
|
||||||
class Picture(Scatter):
|
|
||||||
source = StringProperty(None)
|
|
||||||
|
|
||||||
|
|
||||||
class TakePictureApp(App):
|
|
||||||
def build(self):
|
|
||||||
self.index = 0
|
|
||||||
activity.bind(on_activity_result=self.on_activity_result)
|
|
||||||
|
|
||||||
def get_filename(self):
|
|
||||||
while True:
|
|
||||||
self.index += 1
|
|
||||||
fn = (Environment.getExternalStorageDirectory().getPath() +
|
|
||||||
'/takepicture{}.jpg'.format(self.index))
|
|
||||||
if not exists(fn):
|
|
||||||
return fn
|
|
||||||
|
|
||||||
def take_picture(self):
|
|
||||||
intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
|
|
||||||
self.last_fn = self.get_filename()
|
|
||||||
self.uri = Uri.parse('file://' + self.last_fn)
|
|
||||||
self.uri = cast('android.os.Parcelable', self.uri)
|
|
||||||
intent.putExtra(MediaStore.EXTRA_OUTPUT, self.uri)
|
|
||||||
mActivity.startActivityForResult(intent, 0x123)
|
|
||||||
|
|
||||||
def on_activity_result(self, requestCode, resultCode, intent):
|
|
||||||
if requestCode == 0x123:
|
|
||||||
Clock.schedule_once(partial(self.add_picture, self.last_fn), 0)
|
|
||||||
|
|
||||||
def add_picture(self, fn, *args):
|
|
||||||
im = Image.open(fn)
|
|
||||||
width, height = im.size
|
|
||||||
im.thumbnail((width / 4, height / 4), Image.ANTIALIAS)
|
|
||||||
im.save(fn, quality=95)
|
|
||||||
self.root.add_widget(Picture(source=fn, center=self.root.center))
|
|
||||||
|
|
||||||
def on_pause(self):
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
TakePictureApp().run()
|
|
Before Width: | Height: | Size: 3.5 KiB |
@ -1,40 +0,0 @@
|
|||||||
#:kivy 1.0
|
|
||||||
#:import win kivy.core.window
|
|
||||||
|
|
||||||
Widget:
|
|
||||||
canvas:
|
|
||||||
Color:
|
|
||||||
rgb: .85, .87, .88
|
|
||||||
Rectangle:
|
|
||||||
size: self.size
|
|
||||||
|
|
||||||
Button:
|
|
||||||
text: 'Take a picture'
|
|
||||||
width: self.texture_size[0] + dp(40)
|
|
||||||
height: '48dp'
|
|
||||||
on_release: app.take_picture()
|
|
||||||
|
|
||||||
<Picture>:
|
|
||||||
on_size: self.center = win.Window.center
|
|
||||||
size: image.size
|
|
||||||
size_hint: None, None
|
|
||||||
|
|
||||||
Image:
|
|
||||||
id: image
|
|
||||||
source: root.source
|
|
||||||
|
|
||||||
# create initial image to be 400 pixels width
|
|
||||||
size: 400, 400
|
|
||||||
|
|
||||||
# add shadow background
|
|
||||||
canvas.before:
|
|
||||||
Color:
|
|
||||||
rgba: 1, 1, 1, 1
|
|
||||||
BorderImage:
|
|
||||||
source: 'shadow32.png'
|
|
||||||
border: (36, 36, 36, 36)
|
|
||||||
size:(self.width + 72, self.height + 72)
|
|
||||||
pos: (-36, -36)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
|||||||
'''
|
|
||||||
Widget animation
|
|
||||||
================
|
|
||||||
|
|
||||||
This example demonstrates creating and applying a multi-part animation to
|
|
||||||
a button widget. You should see a button labelled 'plop' that will move with
|
|
||||||
an animation when clicked.
|
|
||||||
'''
|
|
||||||
|
|
||||||
import kivy
|
|
||||||
kivy.require('1.0.7')
|
|
||||||
|
|
||||||
from kivy.animation import Animation
|
|
||||||
from kivy.app import App
|
|
||||||
from kivy.uix.button import Button
|
|
||||||
|
|
||||||
|
|
||||||
class TestApp(App):
|
|
||||||
|
|
||||||
def animate(self, instance):
|
|
||||||
# create an animation object. This object could be stored
|
|
||||||
# and reused each call or reused across different widgets.
|
|
||||||
# += is a sequential step, while &= is in parallel
|
|
||||||
animation = Animation(pos=(100, 100), t='out_bounce')
|
|
||||||
animation += Animation(pos=(200, 100), t='out_bounce')
|
|
||||||
animation &= Animation(size=(500, 500))
|
|
||||||
animation += Animation(size=(100, 50))
|
|
||||||
|
|
||||||
# apply the animation on the button, passed in the "instance" argument
|
|
||||||
# Notice that default 'click' animation (changing the button
|
|
||||||
# color while the mouse is down) is unchanged.
|
|
||||||
animation.start(instance)
|
|
||||||
|
|
||||||
def build(self):
|
|
||||||
# create a button, and attach animate() method as a on_press handler
|
|
||||||
button = Button(size_hint=(None, None), text='plop',
|
|
||||||
on_press=self.animate)
|
|
||||||
return button
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
TestApp().run()
|
|
@ -1,152 +0,0 @@
|
|||||||
'''
|
|
||||||
Suite of Application Builders
|
|
||||||
=============================
|
|
||||||
|
|
||||||
This explores different methods of starting an application. If you run
|
|
||||||
this without a command line parameter, you should see a menu in your terminal.
|
|
||||||
You can also run this with a 'r' parameter to pick a random method.
|
|
||||||
There are lots of logging options to make this easier to debug: the execution
|
|
||||||
order may not be obvious. Each time you run the command, only one kivy
|
|
||||||
application is created.
|
|
||||||
|
|
||||||
This uses the file testkvfile.kv and the file app_suite_data/testkvdir.kv.
|
|
||||||
|
|
||||||
'''
|
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
import sys
|
|
||||||
import re
|
|
||||||
from random import choice
|
|
||||||
|
|
||||||
import kivy
|
|
||||||
kivy.require('1.8.0') # 1.8 is when kv_directory became part of app.
|
|
||||||
from kivy.app import App
|
|
||||||
from kivy.uix.button import Button
|
|
||||||
from kivy.lang import Builder
|
|
||||||
|
|
||||||
from kivy.uix.floatlayout import FloatLayout
|
|
||||||
# Note that importing FloatLayout causes Kivy to execute, including
|
|
||||||
# starting up the Logger and some other messages.
|
|
||||||
print("** In main program, done with imports")
|
|
||||||
|
|
||||||
|
|
||||||
class TestBuildApp(App):
|
|
||||||
""" Use build() function to return a widget. """
|
|
||||||
def build(self):
|
|
||||||
""" Build called by kivy when an App is started.
|
|
||||||
Called after trying to load a .kv file.
|
|
||||||
Returns a new Button as a root widget.
|
|
||||||
"""
|
|
||||||
print("** inside build()")
|
|
||||||
return Button(text='hello from TestBuildApp')
|
|
||||||
|
|
||||||
|
|
||||||
class TestKVFileApp(App):
|
|
||||||
"""
|
|
||||||
Empty class, but name used to find .kv file. The filename is the lowercase
|
|
||||||
version of the class, i.e. 'testkvfileapp.kv'. If not found, it strips
|
|
||||||
off the final 'app', i.e. 'testkvfile.kv'. If not file is found, and no
|
|
||||||
other method sets the self.root, the program will run with an empty screen.
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class TestKVDirApp(App):
|
|
||||||
"""
|
|
||||||
Empty class except for setting class variable kv_directory.
|
|
||||||
This directory sets the directory in which to search for the .kv file.
|
|
||||||
The name of the kv file is still governed by the class name and the .kv
|
|
||||||
file should still have one root widget.
|
|
||||||
"""
|
|
||||||
kv_directory = 'app_suite_data'
|
|
||||||
|
|
||||||
|
|
||||||
class TestKVStringApp(App):
|
|
||||||
"""
|
|
||||||
Use a build() function and use the kivy.lang.Builder function to parse up a
|
|
||||||
Kivy language string.
|
|
||||||
"""
|
|
||||||
def build(self):
|
|
||||||
""" Called by kivy run(). """
|
|
||||||
print("** inside build()")
|
|
||||||
widget = Builder.load_string(
|
|
||||||
"Button:\n text: 'hello from TestKVStringApp'")
|
|
||||||
print("** widget built")
|
|
||||||
return widget
|
|
||||||
|
|
||||||
|
|
||||||
class TestPrebuiltApp(App):
|
|
||||||
""" Use the Builder to create a top level widget at the beginning
|
|
||||||
of the Python program, then use a dummy class for that widget.
|
|
||||||
This costs a bit more in start-up time. """
|
|
||||||
kv = "<Prebuilt>\n Button:\n text:'hello from TestPrebuiltApp'"
|
|
||||||
Builder.load_string(kv)
|
|
||||||
print("** in TestPrebuiltApp, class initialization built <Prebuilt>")
|
|
||||||
|
|
||||||
class Prebuilt(FloatLayout):
|
|
||||||
""" Empty class to cause setting root to <Prebuilt> tag and
|
|
||||||
set inheritence """
|
|
||||||
pass
|
|
||||||
|
|
||||||
def build(self):
|
|
||||||
""" called, returns instance matching tag . """
|
|
||||||
return self.Prebuilt()
|
|
||||||
|
|
||||||
|
|
||||||
def print_class(class_name):
|
|
||||||
""" Read this file and print the section with the class name specified.)"""
|
|
||||||
filename = sys.argv[0]
|
|
||||||
with open(filename) as f:
|
|
||||||
data = f.read()
|
|
||||||
regex = "^(class " + class_name + "\\b.*?)^\\S"
|
|
||||||
match = re.search(regex, data, flags=re.MULTILINE | re.DOTALL)
|
|
||||||
if match:
|
|
||||||
print(match.group(1))
|
|
||||||
|
|
||||||
|
|
||||||
# the __name__ idiom executes when run from command line but not from import.
|
|
||||||
if __name__ == '__main__':
|
|
||||||
dash = "-" * 40
|
|
||||||
|
|
||||||
arg = sys.argv[1][0].lower() if len(sys.argv) > 1 else "h"
|
|
||||||
print(dash)
|
|
||||||
|
|
||||||
if arg == 'r':
|
|
||||||
arg = choice('bfds')
|
|
||||||
|
|
||||||
if arg == 'b':
|
|
||||||
print_class("TestBuildApp")
|
|
||||||
TestBuildApp().run()
|
|
||||||
elif arg == 'f':
|
|
||||||
print_class("TestKVFileApp")
|
|
||||||
TestKVFileApp().run()
|
|
||||||
elif arg == 'd':
|
|
||||||
print_class("TestKVDirApp")
|
|
||||||
TestKVDirApp().run()
|
|
||||||
elif arg == 's':
|
|
||||||
print_class("TestKVStringApp")
|
|
||||||
TestKVStringApp().run()
|
|
||||||
elif arg == 'p':
|
|
||||||
print_class("TestPrebuiltApp")
|
|
||||||
TestPrebuiltApp().run()
|
|
||||||
else: # help
|
|
||||||
print("""
|
|
||||||
This demo runs different application windows based on a command line argument.
|
|
||||||
|
|
||||||
Try using one of these:
|
|
||||||
b - Use build() method to return a widget
|
|
||||||
d - Use a kv file from a different directory
|
|
||||||
f - Use a kv file with the widget object
|
|
||||||
p - Use prebuilt widget inside a layout
|
|
||||||
s - Use a kivy language string to create the widget
|
|
||||||
r - pick one of the options at random.
|
|
||||||
|
|
||||||
h - show this help message.
|
|
||||||
|
|
||||||
After closing the application window, this program will exit.
|
|
||||||
While the run() method does return, kivy cannot run another
|
|
||||||
application window after one has been closed.
|
|
||||||
""")
|
|
||||||
|
|
||||||
print(dash)
|
|
||||||
print("This program is gratified to be of use.")
|
|
@ -1,4 +0,0 @@
|
|||||||
#:kivy 1.0
|
|
||||||
|
|
||||||
Button:
|
|
||||||
text: 'Hello from app_suite_data/testkvdir.kv'
|
|
@ -1,24 +0,0 @@
|
|||||||
'''
|
|
||||||
Application example using build() + return
|
|
||||||
==========================================
|
|
||||||
|
|
||||||
An application can be built if you return a widget on build(), or if you set
|
|
||||||
self.root.
|
|
||||||
'''
|
|
||||||
|
|
||||||
import kivy
|
|
||||||
kivy.require('1.0.7')
|
|
||||||
|
|
||||||
from kivy.app import App
|
|
||||||
from kivy.uix.button import Button
|
|
||||||
|
|
||||||
|
|
||||||
class TestApp(App):
|
|
||||||
|
|
||||||
def build(self):
|
|
||||||
# return a Button() as a root widget
|
|
||||||
return Button(text='hello world')
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
TestApp().run()
|
|
@ -1,49 +0,0 @@
|
|||||||
from kivy.app import App
|
|
||||||
from kivy.lang import Builder
|
|
||||||
from kivy.properties import ConfigParserProperty
|
|
||||||
|
|
||||||
KV = '''
|
|
||||||
FloatLayout:
|
|
||||||
BoxLayout:
|
|
||||||
size_hint: .5, .5
|
|
||||||
pos_hint: {'center': (.5, .5)}
|
|
||||||
|
|
||||||
orientation: 'vertical'
|
|
||||||
|
|
||||||
TextInput:
|
|
||||||
text: app.text
|
|
||||||
on_text: app.text = self.text
|
|
||||||
|
|
||||||
Slider:
|
|
||||||
min: 0
|
|
||||||
max: 100
|
|
||||||
value: app.number
|
|
||||||
on_value: app.number = self.value
|
|
||||||
'''
|
|
||||||
|
|
||||||
|
|
||||||
class ConfigApp(App):
|
|
||||||
number = ConfigParserProperty(
|
|
||||||
0, 'general', 'number',
|
|
||||||
'app', val_type=float
|
|
||||||
)
|
|
||||||
text = ConfigParserProperty(
|
|
||||||
'', 'general', 'text',
|
|
||||||
'app', val_type=str
|
|
||||||
)
|
|
||||||
|
|
||||||
def build_config(self, config):
|
|
||||||
config.setdefaults(
|
|
||||||
'general',
|
|
||||||
{
|
|
||||||
'number': 0,
|
|
||||||
'text': 'test'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
def build(self):
|
|
||||||
return Builder.load_string(KV)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
ConfigApp().run()
|
|
@ -1,25 +0,0 @@
|
|||||||
'''
|
|
||||||
Application built from a .kv file
|
|
||||||
==================================
|
|
||||||
|
|
||||||
This shows how to implicitly use a .kv file for your application. You
|
|
||||||
should see a full screen button labelled "Hello from test.kv".
|
|
||||||
|
|
||||||
After Kivy instantiates a subclass of App, it implicitly searches for a .kv
|
|
||||||
file. The file test.kv is selected because the name of the subclass of App is
|
|
||||||
TestApp, which implies that kivy should try to load "test.kv". That file
|
|
||||||
contains a root Widget.
|
|
||||||
'''
|
|
||||||
|
|
||||||
import kivy
|
|
||||||
kivy.require('1.0.7')
|
|
||||||
|
|
||||||
from kivy.app import App
|
|
||||||
|
|
||||||
|
|
||||||
class TestApp(App):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
TestApp().run()
|
|
@ -1,27 +0,0 @@
|
|||||||
'''
|
|
||||||
Application from a .kv in a Template Directory
|
|
||||||
==============================================
|
|
||||||
|
|
||||||
This example shows how you can change the directory for the .kv file. You
|
|
||||||
should see "Hello from template1/test.ky" as a button.
|
|
||||||
|
|
||||||
As kivy instantiates the TestApp subclass of App, the variable kv_directory
|
|
||||||
is set. Kivy then implicitly searches for a .kv file matching the name
|
|
||||||
of the subclass in that directory, finding the file template1/test.kv. That
|
|
||||||
file contains the root widget.
|
|
||||||
|
|
||||||
|
|
||||||
'''
|
|
||||||
|
|
||||||
import kivy
|
|
||||||
kivy.require('1.0.7')
|
|
||||||
|
|
||||||
from kivy.app import App
|
|
||||||
|
|
||||||
|
|
||||||
class TestApp(App):
|
|
||||||
kv_directory = 'template1'
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
TestApp().run()
|
|
@ -1,4 +0,0 @@
|
|||||||
#:kivy 1.0
|
|
||||||
|
|
||||||
Button:
|
|
||||||
text: 'Hello from template1/test.kv'
|
|
@ -1,4 +0,0 @@
|
|||||||
#:kivy 1.0
|
|
||||||
|
|
||||||
Button:
|
|
||||||
text: 'Hello from test.kv'
|
|
@ -1,4 +0,0 @@
|
|||||||
#:kivy 1.0
|
|
||||||
|
|
||||||
Button:
|
|
||||||
text: 'Hello from testkvfile.kv'
|
|
@ -1,59 +0,0 @@
|
|||||||
#:kivy 1.0
|
|
||||||
#:import kivy kivy
|
|
||||||
|
|
||||||
<AudioBackground>:
|
|
||||||
orientation: 'vertical'
|
|
||||||
canvas:
|
|
||||||
Color:
|
|
||||||
rgb: 1, 1, 1
|
|
||||||
Rectangle:
|
|
||||||
source: 'data/images/background.jpg'
|
|
||||||
size: self.size
|
|
||||||
|
|
||||||
BoxLayout:
|
|
||||||
padding: 10
|
|
||||||
spacing: 10
|
|
||||||
size_hint: 1, None
|
|
||||||
pos_hint: {'top': 1}
|
|
||||||
height: 44
|
|
||||||
Image:
|
|
||||||
size_hint: None, None
|
|
||||||
size: 24, 24
|
|
||||||
source: 'data/logo/kivy-icon-24.png'
|
|
||||||
Label:
|
|
||||||
height: 24
|
|
||||||
text_size: self.size
|
|
||||||
color: (1, 1, 1, .8)
|
|
||||||
text: 'Kivy %s - Audio sample' % kivy.__version__
|
|
||||||
valign: 'middle'
|
|
||||||
|
|
||||||
Label:
|
|
||||||
text: 'Audio example'
|
|
||||||
font_size: 32
|
|
||||||
size_hint_y: None
|
|
||||||
|
|
||||||
BoxLayout:
|
|
||||||
Slider:
|
|
||||||
min: 0.0
|
|
||||||
max: 1.0
|
|
||||||
value: 1.0
|
|
||||||
on_value: app.set_volume(self.value)
|
|
||||||
orientation: "vertical"
|
|
||||||
size_hint_x: None
|
|
||||||
width: "48dp"
|
|
||||||
|
|
||||||
StackLayout:
|
|
||||||
id: sl
|
|
||||||
|
|
||||||
Button:
|
|
||||||
text: 'Stop and release all audio'
|
|
||||||
size_hint_y: None
|
|
||||||
height: '50sp'
|
|
||||||
on_press: app.release_audio()
|
|
||||||
|
|
||||||
<AudioButton>:
|
|
||||||
size_hint: None,0.333
|
|
||||||
width: self.height
|
|
||||||
text_size: self.size
|
|
||||||
font_size: '12sp'
|
|
||||||
valign: 'middle'
|
|
@ -1,81 +0,0 @@
|
|||||||
'''
|
|
||||||
Audio example
|
|
||||||
=============
|
|
||||||
|
|
||||||
This example plays sounds of different formats. You should see a grid of
|
|
||||||
buttons labelled with filenames. Clicking on the buttons will play, or
|
|
||||||
restart, each sound. Not all sound formats will play on all platforms.
|
|
||||||
|
|
||||||
All the sounds are from the http://woolyss.com/chipmusic-samples.php
|
|
||||||
"THE FREESOUND PROJECT", Under Creative Commons Sampling Plus 1.0 License.
|
|
||||||
|
|
||||||
'''
|
|
||||||
|
|
||||||
import kivy
|
|
||||||
kivy.require('1.0.8')
|
|
||||||
|
|
||||||
from kivy.app import App
|
|
||||||
from kivy.uix.button import Button
|
|
||||||
from kivy.uix.boxlayout import BoxLayout
|
|
||||||
from kivy.core.audio import SoundLoader
|
|
||||||
from kivy.properties import StringProperty, ObjectProperty, NumericProperty
|
|
||||||
from glob import glob
|
|
||||||
from os.path import dirname, join, basename
|
|
||||||
|
|
||||||
|
|
||||||
class AudioButton(Button):
|
|
||||||
|
|
||||||
filename = StringProperty(None)
|
|
||||||
sound = ObjectProperty(None, allownone=True)
|
|
||||||
volume = NumericProperty(1.0)
|
|
||||||
|
|
||||||
def on_press(self):
|
|
||||||
if self.sound is None:
|
|
||||||
self.sound = SoundLoader.load(self.filename)
|
|
||||||
# stop the sound if it's currently playing
|
|
||||||
if self.sound.status != 'stop':
|
|
||||||
self.sound.stop()
|
|
||||||
self.sound.volume = self.volume
|
|
||||||
self.sound.play()
|
|
||||||
|
|
||||||
def release_audio(self):
|
|
||||||
if self.sound:
|
|
||||||
self.sound.stop()
|
|
||||||
self.sound.unload()
|
|
||||||
self.sound = None
|
|
||||||
|
|
||||||
def set_volume(self, volume):
|
|
||||||
self.volume = volume
|
|
||||||
if self.sound:
|
|
||||||
self.sound.volume = volume
|
|
||||||
|
|
||||||
|
|
||||||
class AudioBackground(BoxLayout):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class AudioApp(App):
|
|
||||||
|
|
||||||
def build(self):
|
|
||||||
|
|
||||||
root = AudioBackground(spacing=5)
|
|
||||||
for fn in glob(join(dirname(__file__), '*.wav')):
|
|
||||||
btn = AudioButton(
|
|
||||||
text=basename(fn[:-4]).replace('_', ' '), filename=fn,
|
|
||||||
size_hint=(None, None), halign='center',
|
|
||||||
size=(128, 128), text_size=(118, None))
|
|
||||||
root.ids.sl.add_widget(btn)
|
|
||||||
|
|
||||||
return root
|
|
||||||
|
|
||||||
def release_audio(self):
|
|
||||||
for audiobutton in self.root.ids.sl.children:
|
|
||||||
audiobutton.release_audio()
|
|
||||||
|
|
||||||
def set_volume(self, value):
|
|
||||||
for audiobutton in self.root.ids.sl.children:
|
|
||||||
audiobutton.set_volume(value)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
AudioApp().run()
|
|
@ -1,42 +0,0 @@
|
|||||||
# encoding: utf8
|
|
||||||
|
|
||||||
from kivy.app import App
|
|
||||||
from kivy.core.audio import SoundLoader
|
|
||||||
from kivy.uix.boxlayout import BoxLayout
|
|
||||||
from kivy.uix.button import Button
|
|
||||||
|
|
||||||
from sys import version_info
|
|
||||||
|
|
||||||
|
|
||||||
NOTES = (
|
|
||||||
('Do', 1),
|
|
||||||
('Ré', 9 / 8.),
|
|
||||||
('Mi', 5 / 4.),
|
|
||||||
('Fa', 4 / 3.),
|
|
||||||
('Sol', 3 / 2.),
|
|
||||||
('La', 5 / 3.),
|
|
||||||
('Si', 15 / 8.),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class Test(App):
|
|
||||||
def build(self):
|
|
||||||
self.sound = SoundLoader.load(
|
|
||||||
'/usr/lib64/python{}.{}/test/audiodata/pluck-pcm32.wav'
|
|
||||||
.format(*version_info[0:2])
|
|
||||||
)
|
|
||||||
root = BoxLayout()
|
|
||||||
for octave in range(-2, 3):
|
|
||||||
for note, pitch in NOTES:
|
|
||||||
button = Button(text=note)
|
|
||||||
button.pitch = pitch * 2 ** octave
|
|
||||||
button.bind(on_release=self.play_note)
|
|
||||||
root.add_widget(button)
|
|
||||||
return root
|
|
||||||
|
|
||||||
def play_note(self, button):
|
|
||||||
self.sound.pitch = button.pitch
|
|
||||||
self.sound.play()
|
|
||||||
|
|
||||||
|
|
||||||
Test().run()
|
|
@ -1,59 +0,0 @@
|
|||||||
'''
|
|
||||||
Camera Example
|
|
||||||
==============
|
|
||||||
|
|
||||||
This example demonstrates a simple use of the camera. It shows a window with
|
|
||||||
a buttoned labelled 'play' to turn the camera on and off. Note that
|
|
||||||
not finding a camera, perhaps because gstreamer is not installed, will
|
|
||||||
throw an exception during the kv language processing.
|
|
||||||
|
|
||||||
'''
|
|
||||||
|
|
||||||
# Uncomment these lines to see all the messages
|
|
||||||
# from kivy.logger import Logger
|
|
||||||
# import logging
|
|
||||||
# Logger.setLevel(logging.TRACE)
|
|
||||||
|
|
||||||
from kivy.app import App
|
|
||||||
from kivy.lang import Builder
|
|
||||||
from kivy.uix.boxlayout import BoxLayout
|
|
||||||
import time
|
|
||||||
Builder.load_string('''
|
|
||||||
<CameraClick>:
|
|
||||||
orientation: 'vertical'
|
|
||||||
Camera:
|
|
||||||
id: camera
|
|
||||||
resolution: (640, 480)
|
|
||||||
play: False
|
|
||||||
ToggleButton:
|
|
||||||
text: 'Play'
|
|
||||||
on_press: camera.play = not camera.play
|
|
||||||
size_hint_y: None
|
|
||||||
height: '48dp'
|
|
||||||
Button:
|
|
||||||
text: 'Capture'
|
|
||||||
size_hint_y: None
|
|
||||||
height: '48dp'
|
|
||||||
on_press: root.capture()
|
|
||||||
''')
|
|
||||||
|
|
||||||
|
|
||||||
class CameraClick(BoxLayout):
|
|
||||||
def capture(self):
|
|
||||||
'''
|
|
||||||
Function to capture the images and give them the names
|
|
||||||
according to their captured time and date.
|
|
||||||
'''
|
|
||||||
camera = self.ids['camera']
|
|
||||||
timestr = time.strftime("%Y%m%d_%H%M%S")
|
|
||||||
camera.export_to_png("IMG_{}.png".format(timestr))
|
|
||||||
print("Captured")
|
|
||||||
|
|
||||||
|
|
||||||
class TestCamera(App):
|
|
||||||
|
|
||||||
def build(self):
|
|
||||||
return CameraClick()
|
|
||||||
|
|
||||||
|
|
||||||
TestCamera().run()
|
|
@ -1,105 +0,0 @@
|
|||||||
'''
|
|
||||||
Bezier Example
|
|
||||||
==============
|
|
||||||
|
|
||||||
This example shows a closed Bezier curve computed from a polygon. You
|
|
||||||
should see a purple polygon, a red bezier curve computed from the polygon,
|
|
||||||
and two sliders. You can drag points on the polygon to recompute the curve.
|
|
||||||
The two sliders control the dash length of the dashed lines making up the two
|
|
||||||
shapes.
|
|
||||||
|
|
||||||
'''
|
|
||||||
from kivy.app import App
|
|
||||||
from kivy.uix.floatlayout import FloatLayout
|
|
||||||
from kivy.uix.slider import Slider
|
|
||||||
from kivy.graphics import Color, Bezier, Line
|
|
||||||
|
|
||||||
|
|
||||||
class BezierTest(FloatLayout):
|
|
||||||
|
|
||||||
def __init__(self, points=[], loop=False, *args, **kwargs):
|
|
||||||
super(BezierTest, self).__init__(*args, **kwargs)
|
|
||||||
self.d = 10 # pixel tolerance when clicking on a point
|
|
||||||
self.points = points
|
|
||||||
self.loop = loop
|
|
||||||
self.current_point = None # index of point being dragged
|
|
||||||
|
|
||||||
with self.canvas:
|
|
||||||
Color(1.0, 0.0, 0.0)
|
|
||||||
|
|
||||||
self.bezier = Bezier(
|
|
||||||
points=self.points,
|
|
||||||
segments=150,
|
|
||||||
loop=self.loop,
|
|
||||||
dash_length=100,
|
|
||||||
dash_offset=10)
|
|
||||||
|
|
||||||
Color(1.0, 0.0, 1.0)
|
|
||||||
self.line = Line(
|
|
||||||
points=self.points + self.points[:2],
|
|
||||||
dash_offset=10,
|
|
||||||
dash_length=100)
|
|
||||||
|
|
||||||
s = Slider(y=0, pos_hint={'x': .3}, size_hint=(.7, None), height=50)
|
|
||||||
s.bind(value=self._set_bezier_dash_offset)
|
|
||||||
self.add_widget(s)
|
|
||||||
|
|
||||||
s = Slider(y=50, pos_hint={'x': .3}, size_hint=(.7, None), height=50)
|
|
||||||
s.bind(value=self._set_line_dash_offset)
|
|
||||||
self.add_widget(s)
|
|
||||||
|
|
||||||
def _set_bezier_dash_offset(self, instance, value):
|
|
||||||
# effect to reduce length while increase offset
|
|
||||||
self.bezier.dash_length = 100 - value
|
|
||||||
self.bezier.dash_offset = value
|
|
||||||
|
|
||||||
def _set_line_dash_offset(self, instance, value):
|
|
||||||
# effect to reduce length while increase offset
|
|
||||||
self.line.dash_length = 100 - value
|
|
||||||
self.line.dash_offset = value
|
|
||||||
|
|
||||||
def on_touch_down(self, touch):
|
|
||||||
if self.collide_point(touch.pos[0], touch.pos[1]):
|
|
||||||
for i, p in enumerate(list(zip(self.points[::2],
|
|
||||||
self.points[1::2]))):
|
|
||||||
if (abs(touch.pos[0] - self.pos[0] - p[0]) < self.d and
|
|
||||||
abs(touch.pos[1] - self.pos[1] - p[1]) < self.d):
|
|
||||||
self.current_point = i + 1
|
|
||||||
return True
|
|
||||||
return super(BezierTest, self).on_touch_down(touch)
|
|
||||||
|
|
||||||
def on_touch_up(self, touch):
|
|
||||||
if self.collide_point(touch.pos[0], touch.pos[1]):
|
|
||||||
if self.current_point:
|
|
||||||
self.current_point = None
|
|
||||||
return True
|
|
||||||
return super(BezierTest, self).on_touch_up(touch)
|
|
||||||
|
|
||||||
def on_touch_move(self, touch):
|
|
||||||
if self.collide_point(touch.pos[0], touch.pos[1]):
|
|
||||||
c = self.current_point
|
|
||||||
if c:
|
|
||||||
self.points[(c - 1) * 2] = touch.pos[0] - self.pos[0]
|
|
||||||
self.points[(c - 1) * 2 + 1] = touch.pos[1] - self.pos[1]
|
|
||||||
self.bezier.points = self.points
|
|
||||||
self.line.points = self.points + self.points[:2]
|
|
||||||
return True
|
|
||||||
return super(BezierTest, self).on_touch_move(touch)
|
|
||||||
|
|
||||||
|
|
||||||
class Main(App):
|
|
||||||
|
|
||||||
def build(self):
|
|
||||||
from math import cos, sin, radians
|
|
||||||
x = y = 150
|
|
||||||
z = 100
|
|
||||||
# Pacman !
|
|
||||||
points = [x, y]
|
|
||||||
for i in range(45, 360, 45):
|
|
||||||
i = radians(i)
|
|
||||||
points.extend([x + cos(i) * z, y + sin(i) * z])
|
|
||||||
return BezierTest(points=points, loop=True)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
Main().run()
|
|
@ -1,72 +0,0 @@
|
|||||||
'''
|
|
||||||
Canvas stress
|
|
||||||
=============
|
|
||||||
|
|
||||||
This example tests the performance of our Graphics engine by drawing large
|
|
||||||
numbers of small squares. You should see a black canvas with buttons and a
|
|
||||||
label at the bottom. Pressing the buttons adds small colored squares to the
|
|
||||||
canvas.
|
|
||||||
|
|
||||||
'''
|
|
||||||
|
|
||||||
from kivy.uix.button import Button
|
|
||||||
from kivy.uix.widget import Widget
|
|
||||||
from kivy.uix.label import Label
|
|
||||||
from kivy.uix.boxlayout import BoxLayout
|
|
||||||
from kivy.app import App
|
|
||||||
from kivy.graphics import Color, Rectangle
|
|
||||||
from random import random as r
|
|
||||||
from functools import partial
|
|
||||||
|
|
||||||
|
|
||||||
class StressCanvasApp(App):
|
|
||||||
|
|
||||||
def add_rects(self, label, wid, count, *largs):
|
|
||||||
label.text = str(int(label.text) + count)
|
|
||||||
with wid.canvas:
|
|
||||||
for x in range(count):
|
|
||||||
Color(r(), 1, 1, mode='hsv')
|
|
||||||
Rectangle(pos=(r() * wid.width + wid.x,
|
|
||||||
r() * wid.height + wid.y), size=(20, 20))
|
|
||||||
|
|
||||||
def double_rects(self, label, wid, *largs):
|
|
||||||
count = int(label.text)
|
|
||||||
self.add_rects(label, wid, count, *largs)
|
|
||||||
|
|
||||||
def reset_rects(self, label, wid, *largs):
|
|
||||||
label.text = '0'
|
|
||||||
wid.canvas.clear()
|
|
||||||
|
|
||||||
def build(self):
|
|
||||||
wid = Widget()
|
|
||||||
|
|
||||||
label = Label(text='0')
|
|
||||||
|
|
||||||
btn_add100 = Button(text='+ 100 rects',
|
|
||||||
on_press=partial(self.add_rects, label, wid, 100))
|
|
||||||
|
|
||||||
btn_add500 = Button(text='+ 500 rects',
|
|
||||||
on_press=partial(self.add_rects, label, wid, 500))
|
|
||||||
|
|
||||||
btn_double = Button(text='x 2',
|
|
||||||
on_press=partial(self.double_rects, label, wid))
|
|
||||||
|
|
||||||
btn_reset = Button(text='Reset',
|
|
||||||
on_press=partial(self.reset_rects, label, wid))
|
|
||||||
|
|
||||||
layout = BoxLayout(size_hint=(1, None), height=50)
|
|
||||||
layout.add_widget(btn_add100)
|
|
||||||
layout.add_widget(btn_add500)
|
|
||||||
layout.add_widget(btn_double)
|
|
||||||
layout.add_widget(btn_reset)
|
|
||||||
layout.add_widget(label)
|
|
||||||
|
|
||||||
root = BoxLayout(orientation='vertical')
|
|
||||||
root.add_widget(wid)
|
|
||||||
root.add_widget(layout)
|
|
||||||
|
|
||||||
return root
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
StressCanvasApp().run()
|
|
@ -1,84 +0,0 @@
|
|||||||
'''
|
|
||||||
Circle Example
|
|
||||||
==============
|
|
||||||
|
|
||||||
This example exercises circle (ellipse) drawing. You should see sliders at the
|
|
||||||
top of the screen with the Kivy logo below it. The sliders control the
|
|
||||||
angle start and stop and the height and width scales. There is a button
|
|
||||||
to reset the sliders. The logo used for the circle's background image is
|
|
||||||
from the kivy/data directory. The entire example is coded in the
|
|
||||||
kv language description.
|
|
||||||
'''
|
|
||||||
|
|
||||||
from kivy.app import App
|
|
||||||
from kivy.lang import Builder
|
|
||||||
|
|
||||||
kv = '''
|
|
||||||
BoxLayout:
|
|
||||||
orientation: 'vertical'
|
|
||||||
BoxLayout:
|
|
||||||
size_hint_y: None
|
|
||||||
height: sp(100)
|
|
||||||
BoxLayout:
|
|
||||||
orientation: 'vertical'
|
|
||||||
Slider:
|
|
||||||
id: e1
|
|
||||||
min: -360.
|
|
||||||
max: 360.
|
|
||||||
Label:
|
|
||||||
text: 'angle_start = {}'.format(e1.value)
|
|
||||||
BoxLayout:
|
|
||||||
orientation: 'vertical'
|
|
||||||
Slider:
|
|
||||||
id: e2
|
|
||||||
min: -360.
|
|
||||||
max: 360.
|
|
||||||
value: 360
|
|
||||||
Label:
|
|
||||||
text: 'angle_end = {}'.format(e2.value)
|
|
||||||
|
|
||||||
BoxLayout:
|
|
||||||
size_hint_y: None
|
|
||||||
height: sp(100)
|
|
||||||
BoxLayout:
|
|
||||||
orientation: 'vertical'
|
|
||||||
Slider:
|
|
||||||
id: wm
|
|
||||||
min: 0
|
|
||||||
max: 2
|
|
||||||
value: 1
|
|
||||||
Label:
|
|
||||||
text: 'Width mult. = {}'.format(wm.value)
|
|
||||||
BoxLayout:
|
|
||||||
orientation: 'vertical'
|
|
||||||
Slider:
|
|
||||||
id: hm
|
|
||||||
min: 0
|
|
||||||
max: 2
|
|
||||||
value: 1
|
|
||||||
Label:
|
|
||||||
text: 'Height mult. = {}'.format(hm.value)
|
|
||||||
Button:
|
|
||||||
text: 'Reset ratios'
|
|
||||||
on_press: wm.value = 1; hm.value = 1
|
|
||||||
|
|
||||||
FloatLayout:
|
|
||||||
canvas:
|
|
||||||
Color:
|
|
||||||
rgb: 1, 1, 1
|
|
||||||
Ellipse:
|
|
||||||
pos: 100, 100
|
|
||||||
size: 200 * wm.value, 201 * hm.value
|
|
||||||
source: 'data/logo/kivy-icon-512.png'
|
|
||||||
angle_start: e1.value
|
|
||||||
angle_end: e2.value
|
|
||||||
|
|
||||||
'''
|
|
||||||
|
|
||||||
|
|
||||||
class CircleApp(App):
|
|
||||||
def build(self):
|
|
||||||
return Builder.load_string(kv)
|
|
||||||
|
|
||||||
|
|
||||||
CircleApp().run()
|
|
@ -1,91 +0,0 @@
|
|||||||
'''
|
|
||||||
FBO Canvas
|
|
||||||
==========
|
|
||||||
|
|
||||||
This demonstrates a layout using an FBO (Frame Buffer Off-screen)
|
|
||||||
instead of a plain canvas. You should see a black canvas with a
|
|
||||||
button labelled 'FBO' in the bottom left corner. Clicking it
|
|
||||||
animates the button moving right to left.
|
|
||||||
'''
|
|
||||||
|
|
||||||
__all__ = ('FboFloatLayout', )
|
|
||||||
|
|
||||||
from kivy.graphics import Color, Rectangle, Canvas, ClearBuffers, ClearColor
|
|
||||||
from kivy.graphics.fbo import Fbo
|
|
||||||
from kivy.uix.floatlayout import FloatLayout
|
|
||||||
from kivy.properties import ObjectProperty, NumericProperty
|
|
||||||
from kivy.app import App
|
|
||||||
from kivy.core.window import Window
|
|
||||||
from kivy.animation import Animation
|
|
||||||
from kivy.factory import Factory
|
|
||||||
|
|
||||||
|
|
||||||
class FboFloatLayout(FloatLayout):
|
|
||||||
|
|
||||||
texture = ObjectProperty(None, allownone=True)
|
|
||||||
|
|
||||||
alpha = NumericProperty(1)
|
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
|
||||||
self.canvas = Canvas()
|
|
||||||
with self.canvas:
|
|
||||||
self.fbo = Fbo(size=self.size)
|
|
||||||
self.fbo_color = Color(1, 1, 1, 1)
|
|
||||||
self.fbo_rect = Rectangle()
|
|
||||||
|
|
||||||
with self.fbo:
|
|
||||||
ClearColor(0, 0, 0, 0)
|
|
||||||
ClearBuffers()
|
|
||||||
|
|
||||||
# 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, *largs):
|
|
||||||
# trick to attach graphics instruction to fbo instead of canvas
|
|
||||||
canvas = self.canvas
|
|
||||||
self.canvas = self.fbo
|
|
||||||
ret = super(FboFloatLayout, self).add_widget(*largs)
|
|
||||||
self.canvas = canvas
|
|
||||||
return ret
|
|
||||||
|
|
||||||
def remove_widget(self, *largs):
|
|
||||||
canvas = self.canvas
|
|
||||||
self.canvas = self.fbo
|
|
||||||
super(FboFloatLayout, self).remove_widget(*largs)
|
|
||||||
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
|
|
||||||
|
|
||||||
def on_alpha(self, instance, value):
|
|
||||||
self.fbo_color.rgba = (1, 1, 1, value)
|
|
||||||
|
|
||||||
|
|
||||||
class ScreenLayerApp(App):
|
|
||||||
def build(self):
|
|
||||||
|
|
||||||
f = FboFloatLayout()
|
|
||||||
b = Factory.Button(text="FBO", size_hint=(None, None))
|
|
||||||
f.add_widget(b)
|
|
||||||
|
|
||||||
def anim_btn(*args):
|
|
||||||
if b.pos[0] == 0:
|
|
||||||
Animation(x=f.width - b.width).start(b)
|
|
||||||
else:
|
|
||||||
Animation(x=0).start(b)
|
|
||||||
b.bind(on_press=anim_btn)
|
|
||||||
|
|
||||||
return f
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
ScreenLayerApp().run()
|
|
Before Width: | Height: | Size: 13 KiB |
@ -1,296 +0,0 @@
|
|||||||
'''
|
|
||||||
Line (SmoothLine) Experiment
|
|
||||||
============================
|
|
||||||
|
|
||||||
This demonstrates the experimental and unfinished SmoothLine feature
|
|
||||||
for fast line drawing. You should see a multi-segment
|
|
||||||
path at the top of the screen, and sliders and buttons along the bottom.
|
|
||||||
You can click to add new points to the segment, change the transparency
|
|
||||||
and width of the line, or hit 'Animate' to see a set of sine and cosine
|
|
||||||
animations. The Cap and Joint buttons don't work: SmoothLine has not
|
|
||||||
implemented these features yet.
|
|
||||||
'''
|
|
||||||
|
|
||||||
from kivy.app import App
|
|
||||||
from kivy.properties import OptionProperty, NumericProperty, ListProperty, \
|
|
||||||
BooleanProperty
|
|
||||||
from kivy.uix.floatlayout import FloatLayout
|
|
||||||
from kivy.lang import Builder
|
|
||||||
from kivy.clock import Clock
|
|
||||||
from math import cos, sin
|
|
||||||
|
|
||||||
Builder.load_string('''
|
|
||||||
<LinePlayground>:
|
|
||||||
canvas:
|
|
||||||
Color:
|
|
||||||
rgba: .4, .4, 1, root.alpha
|
|
||||||
Line:
|
|
||||||
points: self.points
|
|
||||||
joint: self.joint
|
|
||||||
cap: self.cap
|
|
||||||
width: self.linewidth
|
|
||||||
close: self.close
|
|
||||||
dash_length: self.dash_length
|
|
||||||
dash_offset: self.dash_offset
|
|
||||||
dashes: self.dashes
|
|
||||||
Color:
|
|
||||||
rgba: .8, .8, .8, root.alpha_controlline
|
|
||||||
Line:
|
|
||||||
points: self.points
|
|
||||||
close: self.close
|
|
||||||
dash_length: self.dash_length
|
|
||||||
dash_offset: self.dash_offset
|
|
||||||
dashes: self.dashes
|
|
||||||
Color:
|
|
||||||
rgba: 1, .4, .4, root.alpha
|
|
||||||
Line:
|
|
||||||
points: self.points2
|
|
||||||
joint: self.joint
|
|
||||||
cap: self.cap
|
|
||||||
width: self.linewidth
|
|
||||||
close: self.close
|
|
||||||
dash_length: self.dash_length
|
|
||||||
dash_offset: self.dash_offset
|
|
||||||
dashes: self.dashes
|
|
||||||
|
|
||||||
GridLayout:
|
|
||||||
cols: 2
|
|
||||||
size_hint: 1, None
|
|
||||||
height: 44 * 5
|
|
||||||
|
|
||||||
GridLayout:
|
|
||||||
cols: 2
|
|
||||||
|
|
||||||
Label:
|
|
||||||
text: 'Alpha'
|
|
||||||
Slider:
|
|
||||||
value: root.alpha
|
|
||||||
on_value: root.alpha = float(args[1])
|
|
||||||
min: 0.
|
|
||||||
max: 1.
|
|
||||||
Label:
|
|
||||||
text: 'Alpha Control Line'
|
|
||||||
Slider:
|
|
||||||
value: root.alpha_controlline
|
|
||||||
on_value: root.alpha_controlline = float(args[1])
|
|
||||||
min: 0.
|
|
||||||
max: 1.
|
|
||||||
Label:
|
|
||||||
text: 'Width'
|
|
||||||
Slider:
|
|
||||||
value: root.linewidth
|
|
||||||
on_value: root.linewidth = args[1]
|
|
||||||
min: 1
|
|
||||||
max: 40
|
|
||||||
Label:
|
|
||||||
text: 'Cap'
|
|
||||||
GridLayout:
|
|
||||||
rows: 1
|
|
||||||
ToggleButton:
|
|
||||||
group: 'cap'
|
|
||||||
text: 'none'
|
|
||||||
on_press: root.cap = self.text
|
|
||||||
ToggleButton:
|
|
||||||
group: 'cap'
|
|
||||||
text: 'round'
|
|
||||||
on_press: root.cap = self.text
|
|
||||||
ToggleButton:
|
|
||||||
group: 'cap'
|
|
||||||
text: 'square'
|
|
||||||
on_press: root.cap = self.text
|
|
||||||
Label:
|
|
||||||
text: 'Joint'
|
|
||||||
GridLayout:
|
|
||||||
rows: 1
|
|
||||||
ToggleButton:
|
|
||||||
group: 'joint'
|
|
||||||
text: 'none'
|
|
||||||
on_press: root.joint = self.text
|
|
||||||
ToggleButton:
|
|
||||||
group: 'joint'
|
|
||||||
text: 'round'
|
|
||||||
on_press: root.joint = self.text
|
|
||||||
ToggleButton:
|
|
||||||
group: 'joint'
|
|
||||||
text: 'miter'
|
|
||||||
on_press: root.joint = self.text
|
|
||||||
ToggleButton:
|
|
||||||
group: 'joint'
|
|
||||||
text: 'bevel'
|
|
||||||
on_press: root.joint = self.text
|
|
||||||
|
|
||||||
Label:
|
|
||||||
text: 'Close'
|
|
||||||
ToggleButton:
|
|
||||||
text: 'Close line'
|
|
||||||
on_press: root.close = self.state == 'down'
|
|
||||||
|
|
||||||
Label:
|
|
||||||
text: 'Dashes'
|
|
||||||
GridLayout:
|
|
||||||
rows: 1
|
|
||||||
ToggleButton:
|
|
||||||
group: 'dashes'
|
|
||||||
text: 'none'
|
|
||||||
state: 'down'
|
|
||||||
allow_no_selection: False
|
|
||||||
size_hint_x: None
|
|
||||||
width: self.texture_size[0]
|
|
||||||
padding_x: '5dp'
|
|
||||||
on_state:
|
|
||||||
if self.state == 'down': root.dashes = []
|
|
||||||
if self.state == 'down': root.dash_length = 1
|
|
||||||
if self.state == 'down': root.dash_offset = 0
|
|
||||||
ToggleButton:
|
|
||||||
id: constant
|
|
||||||
group: 'dashes'
|
|
||||||
text: 'Constant: '
|
|
||||||
allow_no_selection: False
|
|
||||||
size_hint_x: None
|
|
||||||
width: self.texture_size[0]
|
|
||||||
padding_x: '5dp'
|
|
||||||
on_state:
|
|
||||||
if self.state == 'down': root.dashes = []
|
|
||||||
if self.state == 'down': root.dash_length = \
|
|
||||||
int(dash_len.text or 1)
|
|
||||||
if self.state == 'down': root.dash_offset = \
|
|
||||||
int(dash_offset.text or 0)
|
|
||||||
Label:
|
|
||||||
text: 'len'
|
|
||||||
size_hint_x: None
|
|
||||||
width: self.texture_size[0]
|
|
||||||
padding_x: '5dp'
|
|
||||||
TextInput:
|
|
||||||
id: dash_len
|
|
||||||
size_hint_x: None
|
|
||||||
width: '30dp'
|
|
||||||
input_filter: 'int'
|
|
||||||
multiline: False
|
|
||||||
text: '1'
|
|
||||||
on_text: if constant.state == 'down': \
|
|
||||||
root.dash_length = int(self.text or 1)
|
|
||||||
Label:
|
|
||||||
text: 'offset'
|
|
||||||
size_hint_x: None
|
|
||||||
width: self.texture_size[0]
|
|
||||||
padding_x: '5dp'
|
|
||||||
TextInput:
|
|
||||||
id: dash_offset
|
|
||||||
size_hint_x: None
|
|
||||||
width: '30dp'
|
|
||||||
input_filter: 'int'
|
|
||||||
multiline: False
|
|
||||||
text: '0'
|
|
||||||
on_text: if constant.state == 'down': \
|
|
||||||
root.dash_offset = int(self.text or 0)
|
|
||||||
ToggleButton:
|
|
||||||
id: dash_list
|
|
||||||
group: 'dashes'
|
|
||||||
text: 'List: '
|
|
||||||
allow_no_selection: False
|
|
||||||
size_hint_x: None
|
|
||||||
width: self.texture_size[0]
|
|
||||||
padding_x: '5dp'
|
|
||||||
on_state:
|
|
||||||
if self.state == 'down': root.dashes = list(map(lambda\
|
|
||||||
x: int(x or 0), dash_list_in.text.split(',')))
|
|
||||||
if self.state == 'down': root.dash_length = 1
|
|
||||||
if self.state == 'down': root.dash_offset = 0
|
|
||||||
TextInput:
|
|
||||||
id: dash_list_in
|
|
||||||
size_hint_x: None
|
|
||||||
width: '180dp'
|
|
||||||
multiline: False
|
|
||||||
text: '4,3,10,15'
|
|
||||||
on_text: if dash_list.state == 'down': root.dashes = \
|
|
||||||
list(map(lambda x: int(x or 0), self.text.split(',')))
|
|
||||||
|
|
||||||
AnchorLayout:
|
|
||||||
GridLayout:
|
|
||||||
cols: 1
|
|
||||||
size_hint: None, None
|
|
||||||
size: self.minimum_size
|
|
||||||
ToggleButton:
|
|
||||||
size_hint: None, None
|
|
||||||
size: 100, 44
|
|
||||||
text: 'Animate'
|
|
||||||
on_state: root.animate(self.state == 'down')
|
|
||||||
Button:
|
|
||||||
size_hint: None, None
|
|
||||||
size: 100, 44
|
|
||||||
text: 'Clear'
|
|
||||||
on_press: root.points = root.points2 = []
|
|
||||||
|
|
||||||
''')
|
|
||||||
|
|
||||||
|
|
||||||
class LinePlayground(FloatLayout):
|
|
||||||
|
|
||||||
alpha_controlline = NumericProperty(1.0)
|
|
||||||
alpha = NumericProperty(0.5)
|
|
||||||
close = BooleanProperty(False)
|
|
||||||
points = ListProperty([(500, 500),
|
|
||||||
[300, 300, 500, 300],
|
|
||||||
[500, 400, 600, 400]])
|
|
||||||
points2 = ListProperty([])
|
|
||||||
joint = OptionProperty('none', options=('round', 'miter', 'bevel', 'none'))
|
|
||||||
cap = OptionProperty('none', options=('round', 'square', 'none'))
|
|
||||||
linewidth = NumericProperty(10.0)
|
|
||||||
dt = NumericProperty(0)
|
|
||||||
dash_length = NumericProperty(1)
|
|
||||||
dash_offset = NumericProperty(0)
|
|
||||||
dashes = ListProperty([])
|
|
||||||
|
|
||||||
_update_points_animation_ev = None
|
|
||||||
|
|
||||||
def on_touch_down(self, touch):
|
|
||||||
if super(LinePlayground, self).on_touch_down(touch):
|
|
||||||
return True
|
|
||||||
touch.grab(self)
|
|
||||||
self.points.append(touch.pos)
|
|
||||||
return True
|
|
||||||
|
|
||||||
def on_touch_move(self, touch):
|
|
||||||
if touch.grab_current is self:
|
|
||||||
self.points[-1] = touch.pos
|
|
||||||
return True
|
|
||||||
return super(LinePlayground, self).on_touch_move(touch)
|
|
||||||
|
|
||||||
def on_touch_up(self, touch):
|
|
||||||
if touch.grab_current is self:
|
|
||||||
touch.ungrab(self)
|
|
||||||
return True
|
|
||||||
return super(LinePlayground, self).on_touch_up(touch)
|
|
||||||
|
|
||||||
def animate(self, do_animation):
|
|
||||||
if do_animation:
|
|
||||||
self._update_points_animation_ev = Clock.schedule_interval(
|
|
||||||
self.update_points_animation, 0)
|
|
||||||
elif self._update_points_animation_ev is not None:
|
|
||||||
self._update_points_animation_ev.cancel()
|
|
||||||
|
|
||||||
def update_points_animation(self, dt):
|
|
||||||
cy = self.height * 0.6
|
|
||||||
cx = self.width * 0.1
|
|
||||||
w = self.width * 0.8
|
|
||||||
step = 20
|
|
||||||
points = []
|
|
||||||
points2 = []
|
|
||||||
self.dt += dt
|
|
||||||
for i in range(int(w / step)):
|
|
||||||
x = i * step
|
|
||||||
points.append(cx + x)
|
|
||||||
points.append(cy + cos(x / w * 8. + self.dt) * self.height * 0.2)
|
|
||||||
points2.append(cx + x)
|
|
||||||
points2.append(cy + sin(x / w * 8. + self.dt) * self.height * 0.2)
|
|
||||||
self.points = points
|
|
||||||
self.points2 = points2
|
|
||||||
|
|
||||||
|
|
||||||
class TestLineApp(App):
|
|
||||||
def build(self):
|
|
||||||
return LinePlayground()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
TestLineApp().run()
|
|
@ -1,183 +0,0 @@
|
|||||||
'''
|
|
||||||
Lines Extended Demo
|
|
||||||
===================
|
|
||||||
|
|
||||||
This demonstrates how to use the extended line drawing routines such
|
|
||||||
as circles, ellipses, and rectangles. You should see a static image of
|
|
||||||
labelled shapes on the screen.
|
|
||||||
'''
|
|
||||||
|
|
||||||
from kivy.app import App
|
|
||||||
from kivy.uix.gridlayout import GridLayout
|
|
||||||
from kivy.uix.widget import Widget
|
|
||||||
from kivy.lang import Builder
|
|
||||||
|
|
||||||
Builder.load_string('''
|
|
||||||
<LineEllipse1>:
|
|
||||||
canvas:
|
|
||||||
Color:
|
|
||||||
rgba: 1, .1, .1, .9
|
|
||||||
Line:
|
|
||||||
width: 2.
|
|
||||||
ellipse: (self.x, self.y, self.width, self.height)
|
|
||||||
Label:
|
|
||||||
center: root.center
|
|
||||||
text: 'Ellipse'
|
|
||||||
|
|
||||||
<LineEllipse2>:
|
|
||||||
canvas:
|
|
||||||
Color:
|
|
||||||
rgba: 1, .1, .1, .9
|
|
||||||
Line:
|
|
||||||
width: 2.
|
|
||||||
ellipse: (self.x, self.y, self.width, self.height, 90, 180)
|
|
||||||
Label:
|
|
||||||
center: root.center
|
|
||||||
text: 'Ellipse from 90 to 180'
|
|
||||||
|
|
||||||
# fun result with low segments!
|
|
||||||
<LineEllipse3>:
|
|
||||||
canvas:
|
|
||||||
Color:
|
|
||||||
rgba: 1, .1, .1, .9
|
|
||||||
Line:
|
|
||||||
width: 2.
|
|
||||||
ellipse: (self.x, self.y, self.width, self.height, 90, 720, 10)
|
|
||||||
Label:
|
|
||||||
center: root.center
|
|
||||||
text: 'Ellipse from 90 to 720\\n10 segments'
|
|
||||||
halign: 'center'
|
|
||||||
|
|
||||||
<LineCircle1>:
|
|
||||||
canvas:
|
|
||||||
Color:
|
|
||||||
rgba: .1, 1, .1, .9
|
|
||||||
Line:
|
|
||||||
width: 2.
|
|
||||||
circle:
|
|
||||||
(self.center_x, self.center_y, min(self.width, self.height)
|
|
||||||
/ 2)
|
|
||||||
Label:
|
|
||||||
center: root.center
|
|
||||||
text: 'Circle'
|
|
||||||
|
|
||||||
<LineCircle2>:
|
|
||||||
canvas:
|
|
||||||
Color:
|
|
||||||
rgba: .1, 1, .1, .9
|
|
||||||
Line:
|
|
||||||
width: 2.
|
|
||||||
circle:
|
|
||||||
(self.center_x, self.center_y, min(self.width, self.height)
|
|
||||||
/ 2, 90, 180)
|
|
||||||
Label:
|
|
||||||
center: root.center
|
|
||||||
text: 'Circle from 90 to 180'
|
|
||||||
|
|
||||||
<LineCircle3>:
|
|
||||||
canvas:
|
|
||||||
Color:
|
|
||||||
rgba: .1, 1, .1, .9
|
|
||||||
Line:
|
|
||||||
width: 2.
|
|
||||||
circle:
|
|
||||||
(self.center_x, self.center_y, min(self.width, self.height)
|
|
||||||
/ 2, 90, 180, 10)
|
|
||||||
Label:
|
|
||||||
center: root.center
|
|
||||||
text: 'Circle from 90 to 180\\n10 segments'
|
|
||||||
halign: 'center'
|
|
||||||
|
|
||||||
<LineCircle4>:
|
|
||||||
canvas:
|
|
||||||
Color:
|
|
||||||
rgba: .1, 1, .1, .9
|
|
||||||
Line:
|
|
||||||
width: 2.
|
|
||||||
circle:
|
|
||||||
(self.center_x, self.center_y, min(self.width, self.height)
|
|
||||||
/ 2, 0, 360)
|
|
||||||
Label:
|
|
||||||
center: root.center
|
|
||||||
text: 'Circle from 0 to 360'
|
|
||||||
halign: 'center'
|
|
||||||
|
|
||||||
<LineRectangle>:
|
|
||||||
canvas:
|
|
||||||
Color:
|
|
||||||
rgba: .1, .1, 1, .9
|
|
||||||
Line:
|
|
||||||
width: 2.
|
|
||||||
rectangle: (self.x, self.y, self.width, self.height)
|
|
||||||
Label:
|
|
||||||
center: root.center
|
|
||||||
text: 'Rectangle'
|
|
||||||
|
|
||||||
<LineBezier>:
|
|
||||||
canvas:
|
|
||||||
Color:
|
|
||||||
rgba: .1, .1, 1, .9
|
|
||||||
Line:
|
|
||||||
width: 2.
|
|
||||||
bezier:
|
|
||||||
(self.x, self.y, self.center_x - 40, self.y + 100,
|
|
||||||
self.center_x + 40, self.y - 100, self.right, self.y)
|
|
||||||
Label:
|
|
||||||
center: root.center
|
|
||||||
text: 'Bezier'
|
|
||||||
''')
|
|
||||||
|
|
||||||
|
|
||||||
class LineEllipse1(Widget):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class LineEllipse2(Widget):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class LineEllipse3(Widget):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class LineCircle1(Widget):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class LineCircle2(Widget):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class LineCircle3(Widget):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class LineCircle4(Widget):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class LineRectangle(Widget):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class LineBezier(Widget):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class LineExtendedApp(App):
|
|
||||||
def build(self):
|
|
||||||
root = GridLayout(cols=2, padding=50, spacing=50)
|
|
||||||
root.add_widget(LineEllipse1())
|
|
||||||
root.add_widget(LineEllipse2())
|
|
||||||
root.add_widget(LineEllipse3())
|
|
||||||
root.add_widget(LineCircle1())
|
|
||||||
root.add_widget(LineCircle2())
|
|
||||||
root.add_widget(LineCircle3())
|
|
||||||
root.add_widget(LineCircle4())
|
|
||||||
root.add_widget(LineRectangle())
|
|
||||||
root.add_widget(LineBezier())
|
|
||||||
return root
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
LineExtendedApp().run()
|
|
@ -1,57 +0,0 @@
|
|||||||
'''
|
|
||||||
Mesh test
|
|
||||||
=========
|
|
||||||
|
|
||||||
This demonstrates the use of a mesh mode to distort an image. You should see
|
|
||||||
a line of buttons across the bottom of a canvas. Pressing them displays
|
|
||||||
the mesh, a small circle of points, with different mesh.mode settings.
|
|
||||||
'''
|
|
||||||
|
|
||||||
from kivy.uix.button import Button
|
|
||||||
from kivy.uix.widget import Widget
|
|
||||||
from kivy.uix.boxlayout import BoxLayout
|
|
||||||
from kivy.app import App
|
|
||||||
from kivy.graphics import Mesh
|
|
||||||
from functools import partial
|
|
||||||
from math import cos, sin, pi
|
|
||||||
|
|
||||||
|
|
||||||
class MeshTestApp(App):
|
|
||||||
|
|
||||||
def change_mode(self, mode, *largs):
|
|
||||||
self.mesh.mode = mode
|
|
||||||
|
|
||||||
def build_mesh(self):
|
|
||||||
""" returns a Mesh of a rough circle. """
|
|
||||||
vertices = []
|
|
||||||
indices = []
|
|
||||||
step = 10
|
|
||||||
istep = (pi * 2) / float(step)
|
|
||||||
for i in range(step):
|
|
||||||
x = 300 + cos(istep * i) * 100
|
|
||||||
y = 300 + sin(istep * i) * 100
|
|
||||||
vertices.extend([x, y, 0, 0])
|
|
||||||
indices.append(i)
|
|
||||||
return Mesh(vertices=vertices, indices=indices)
|
|
||||||
|
|
||||||
def build(self):
|
|
||||||
wid = Widget()
|
|
||||||
with wid.canvas:
|
|
||||||
self.mesh = self.build_mesh()
|
|
||||||
|
|
||||||
layout = BoxLayout(size_hint=(1, None), height=50)
|
|
||||||
for mode in ('points', 'line_strip', 'line_loop', 'lines',
|
|
||||||
'triangle_strip', 'triangle_fan'):
|
|
||||||
button = Button(text=mode)
|
|
||||||
button.bind(on_release=partial(self.change_mode, mode))
|
|
||||||
layout.add_widget(button)
|
|
||||||
|
|
||||||
root = BoxLayout(orientation='vertical')
|
|
||||||
root.add_widget(wid)
|
|
||||||
root.add_widget(layout)
|
|
||||||
|
|
||||||
return root
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
MeshTestApp().run()
|
|
@ -1,101 +0,0 @@
|
|||||||
'''
|
|
||||||
Mesh Manipulation Example
|
|
||||||
=========================
|
|
||||||
|
|
||||||
This demonstrates creating a mesh and using it to deform the texture (the
|
|
||||||
kivy log). You should see the kivy logo with a five sliders to right.
|
|
||||||
The sliders change the mesh points' x and y offsets, radius, and a
|
|
||||||
'wobble' deformation's magnitude and speed.
|
|
||||||
|
|
||||||
This example is developed in gabriel's blog post at
|
|
||||||
http://kivy.org/planet/2014/01/kivy-image-manipulations-with-mesh-and-textures/
|
|
||||||
'''
|
|
||||||
|
|
||||||
from kivy.app import App
|
|
||||||
from kivy.lang import Builder
|
|
||||||
from kivy.core.image import Image as CoreImage
|
|
||||||
from kivy.properties import ListProperty, ObjectProperty, NumericProperty
|
|
||||||
from kivy.clock import Clock
|
|
||||||
from kivy.core.window import Window
|
|
||||||
from math import sin, cos, pi
|
|
||||||
|
|
||||||
|
|
||||||
kv = '''
|
|
||||||
BoxLayout:
|
|
||||||
Widget:
|
|
||||||
canvas:
|
|
||||||
Color:
|
|
||||||
rgba: 1, 1, 1, 1
|
|
||||||
Mesh:
|
|
||||||
vertices: app.mesh_points
|
|
||||||
indices: range(len(app.mesh_points) // 4)
|
|
||||||
texture: app.mesh_texture
|
|
||||||
mode: 'triangle_fan'
|
|
||||||
BoxLayout:
|
|
||||||
orientation: 'vertical'
|
|
||||||
size_hint_x: None
|
|
||||||
width: 100
|
|
||||||
Slider:
|
|
||||||
value: app.offset_x
|
|
||||||
on_value: app.offset_x = args[1]
|
|
||||||
min: -1
|
|
||||||
max: 1
|
|
||||||
Slider:
|
|
||||||
value: app.offset_y
|
|
||||||
on_value: app.offset_y = args[1]
|
|
||||||
min: -1
|
|
||||||
max: 1
|
|
||||||
Slider:
|
|
||||||
value: app.radius
|
|
||||||
on_value: app.radius = args[1]
|
|
||||||
min: 10
|
|
||||||
max: 1000
|
|
||||||
Slider:
|
|
||||||
value: app.sin_wobble
|
|
||||||
on_value: app.sin_wobble = args[1]
|
|
||||||
min: -50
|
|
||||||
max: 50
|
|
||||||
Slider:
|
|
||||||
value: app.sin_wobble_speed
|
|
||||||
on_value: app.sin_wobble_speed = args[1]
|
|
||||||
min: 0
|
|
||||||
max: 50
|
|
||||||
step: 1
|
|
||||||
'''
|
|
||||||
|
|
||||||
|
|
||||||
class MeshBallApp(App):
|
|
||||||
mesh_points = ListProperty([])
|
|
||||||
mesh_texture = ObjectProperty(None)
|
|
||||||
radius = NumericProperty(500)
|
|
||||||
offset_x = NumericProperty(.5)
|
|
||||||
offset_y = NumericProperty(.5)
|
|
||||||
sin_wobble = NumericProperty(0)
|
|
||||||
sin_wobble_speed = NumericProperty(0)
|
|
||||||
|
|
||||||
def build(self):
|
|
||||||
self.mesh_texture = CoreImage('data/logo/kivy-icon-512.png').texture
|
|
||||||
Clock.schedule_interval(self.update_points, 0)
|
|
||||||
return Builder.load_string(kv)
|
|
||||||
|
|
||||||
def update_points(self, *args):
|
|
||||||
""" replace self.mesh_points based on current slider positions.
|
|
||||||
Called continuously by a timer because this only sample code.
|
|
||||||
"""
|
|
||||||
points = [Window.width / 2, Window.height / 2, .5, .5]
|
|
||||||
i = 0
|
|
||||||
while i < 2 * pi:
|
|
||||||
i += 0.01 * pi
|
|
||||||
points.extend([
|
|
||||||
Window.width / 2 + cos(i) * (self.radius + self.sin_wobble *
|
|
||||||
sin(i * self.sin_wobble_speed)),
|
|
||||||
Window.height / 2 + sin(i) * (self.radius + self.sin_wobble *
|
|
||||||
sin(i * self.sin_wobble_speed)),
|
|
||||||
self.offset_x + sin(i),
|
|
||||||
self.offset_y + cos(i)])
|
|
||||||
|
|
||||||
self.mesh_points = points
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
MeshBallApp().run()
|
|
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.5 KiB |
@ -1,110 +0,0 @@
|
|||||||
'''
|
|
||||||
Multitexture Example
|
|
||||||
====================
|
|
||||||
|
|
||||||
This example blends two textures: the image mtexture1.png of the letter K
|
|
||||||
and the image mtexture2.png of an orange circle. You should see an orange
|
|
||||||
K clipped to a circle. It uses a custom shader, written in glsl
|
|
||||||
(OpenGL Shading Language), stored in a local string.
|
|
||||||
|
|
||||||
Note the image mtexture1.png is a white 'K' on a transparent background, which
|
|
||||||
makes it hard to see.
|
|
||||||
'''
|
|
||||||
|
|
||||||
from kivy.clock import Clock
|
|
||||||
from kivy.app import App
|
|
||||||
from kivy.uix.widget import Widget
|
|
||||||
from kivy.uix.floatlayout import FloatLayout
|
|
||||||
from kivy.lang import Builder
|
|
||||||
from kivy.core.window import Window
|
|
||||||
from kivy.graphics import RenderContext, Color, Rectangle, BindTexture
|
|
||||||
|
|
||||||
|
|
||||||
fs_multitexture = '''
|
|
||||||
$HEADER$
|
|
||||||
|
|
||||||
// New uniform that will receive texture at index 1
|
|
||||||
uniform sampler2D texture1;
|
|
||||||
|
|
||||||
void main(void) {
|
|
||||||
|
|
||||||
// multiple current color with both texture (0 and 1).
|
|
||||||
// currently, both will use exactly the same texture coordinates.
|
|
||||||
gl_FragColor = frag_color * \
|
|
||||||
texture2D(texture0, tex_coord0) * \
|
|
||||||
texture2D(texture1, tex_coord0);
|
|
||||||
}
|
|
||||||
'''
|
|
||||||
|
|
||||||
|
|
||||||
kv = """
|
|
||||||
<MultitextureLayout>:
|
|
||||||
|
|
||||||
Image:
|
|
||||||
source: "mtexture1.png"
|
|
||||||
size_hint: .3,.3
|
|
||||||
id: 1
|
|
||||||
pos: 0,200
|
|
||||||
Image:
|
|
||||||
source: "mtexture2.png"
|
|
||||||
size_hint: .3,.3
|
|
||||||
id: 2
|
|
||||||
pos: 200,200
|
|
||||||
|
|
||||||
MultitextureWidget:
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
Builder.load_string(kv)
|
|
||||||
|
|
||||||
|
|
||||||
class MultitextureWidget(Widget):
|
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
|
||||||
self.canvas = RenderContext()
|
|
||||||
# setting shader.fs to new source code automatically compiles it.
|
|
||||||
self.canvas.shader.fs = fs_multitexture
|
|
||||||
with self.canvas:
|
|
||||||
Color(1, 1, 1)
|
|
||||||
|
|
||||||
# here, we are binding a custom texture at index 1
|
|
||||||
# this will be used as texture1 in shader.
|
|
||||||
# The filenames are misleading: they do not correspond to the
|
|
||||||
# index here or in the shader.
|
|
||||||
BindTexture(source='mtexture2.png', index=1)
|
|
||||||
|
|
||||||
# create a rectangle with texture (will be at index 0)
|
|
||||||
Rectangle(size=(150, 150), source='mtexture1.png', pos=(500, 200))
|
|
||||||
|
|
||||||
# set the texture1 to use texture index 1
|
|
||||||
self.canvas['texture1'] = 1
|
|
||||||
|
|
||||||
# call the constructor of parent
|
|
||||||
# if they are any graphics objects, they will be added on our new
|
|
||||||
# canvas
|
|
||||||
super(MultitextureWidget, self).__init__(**kwargs)
|
|
||||||
|
|
||||||
# We'll update our glsl variables in a clock
|
|
||||||
Clock.schedule_interval(self.update_glsl, 0)
|
|
||||||
|
|
||||||
def update_glsl(self, *largs):
|
|
||||||
# This is needed for the default vertex shader.
|
|
||||||
self.canvas['projection_mat'] = Window.render_context['projection_mat']
|
|
||||||
self.canvas['modelview_mat'] = Window.render_context['modelview_mat']
|
|
||||||
|
|
||||||
|
|
||||||
class MultitextureLayout(FloatLayout):
|
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
|
||||||
self.size = kwargs['size']
|
|
||||||
super(MultitextureLayout, self).__init__(**kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class MultitextureApp(App):
|
|
||||||
|
|
||||||
def build(self):
|
|
||||||
return MultitextureLayout(size=(600, 600))
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
MultitextureApp().run()
|
|
@ -1,65 +0,0 @@
|
|||||||
'''
|
|
||||||
Repeat Texture on Resize
|
|
||||||
========================
|
|
||||||
|
|
||||||
This examples repeats the letter 'K' (mtexture1.png) 64 times in a window.
|
|
||||||
You should see 8 rows and 8 columns of white K letters, along a label
|
|
||||||
showing the current size. As you resize the window, it stays an 8x8.
|
|
||||||
This example includes a label with a colored background.
|
|
||||||
|
|
||||||
Note the image mtexture1.png is a white 'K' on a transparent background, which
|
|
||||||
makes it hard to see.
|
|
||||||
'''
|
|
||||||
|
|
||||||
from kivy.app import App
|
|
||||||
from kivy.uix.image import Image
|
|
||||||
from kivy.uix.label import Label
|
|
||||||
from kivy.properties import ObjectProperty, ListProperty
|
|
||||||
from kivy.lang import Builder
|
|
||||||
|
|
||||||
kv = '''
|
|
||||||
<LabelOnBackground>:
|
|
||||||
canvas.before:
|
|
||||||
Color:
|
|
||||||
rgb: self.background
|
|
||||||
Rectangle:
|
|
||||||
pos: self.pos
|
|
||||||
size: self.size
|
|
||||||
|
|
||||||
FloatLayout:
|
|
||||||
canvas.before:
|
|
||||||
Color:
|
|
||||||
rgb: 1, 1, 1
|
|
||||||
Rectangle:
|
|
||||||
pos: self.pos
|
|
||||||
size: self.size
|
|
||||||
texture: app.texture
|
|
||||||
|
|
||||||
LabelOnBackground:
|
|
||||||
text: '{} (try to resize the window)'.format(root.size)
|
|
||||||
color: (0.4, 1, 1, 1)
|
|
||||||
background: (.3, .3, .3)
|
|
||||||
pos_hint: {'center_x': .5, 'center_y': .5 }
|
|
||||||
size_hint: None, None
|
|
||||||
height: 30
|
|
||||||
width: 250
|
|
||||||
|
|
||||||
'''
|
|
||||||
|
|
||||||
|
|
||||||
class LabelOnBackground(Label):
|
|
||||||
background = ListProperty((0.2, 0.2, 0.2))
|
|
||||||
|
|
||||||
|
|
||||||
class RepeatTexture(App):
|
|
||||||
|
|
||||||
texture = ObjectProperty()
|
|
||||||
|
|
||||||
def build(self):
|
|
||||||
self.texture = Image(source='mtexture1.png').texture
|
|
||||||
self.texture.wrap = 'repeat'
|
|
||||||
self.texture.uvsize = (8, 8)
|
|
||||||
return Builder.load_string(kv)
|
|
||||||
|
|
||||||
|
|
||||||
RepeatTexture().run()
|
|
@ -1,35 +0,0 @@
|
|||||||
'''
|
|
||||||
Rotation Example
|
|
||||||
================
|
|
||||||
|
|
||||||
This example rotates a button using PushMatrix and PopMatrix. You should see
|
|
||||||
a static button with the words 'hello world' rotated at a 45 degree angle.
|
|
||||||
'''
|
|
||||||
|
|
||||||
|
|
||||||
from kivy.app import App
|
|
||||||
from kivy.lang import Builder
|
|
||||||
|
|
||||||
kv = '''
|
|
||||||
FloatLayout:
|
|
||||||
|
|
||||||
Button:
|
|
||||||
text: 'hello world'
|
|
||||||
size_hint: None, None
|
|
||||||
pos_hint: {'center_x': .5, 'center_y': .5}
|
|
||||||
canvas.before:
|
|
||||||
PushMatrix
|
|
||||||
Rotate:
|
|
||||||
angle: 45
|
|
||||||
origin: self.center
|
|
||||||
canvas.after:
|
|
||||||
PopMatrix
|
|
||||||
'''
|
|
||||||
|
|
||||||
|
|
||||||
class RotationApp(App):
|
|
||||||
def build(self):
|
|
||||||
return Builder.load_string(kv)
|
|
||||||
|
|
||||||
|
|
||||||
RotationApp().run()
|
|
@ -1,153 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
from kivy.app import App
|
|
||||||
from kivy.uix.widget import Widget
|
|
||||||
from kivy.graphics import Color, Ellipse, Rectangle, RoundedRectangle
|
|
||||||
from kivy.lang import Builder
|
|
||||||
|
|
||||||
TEXTURE = 'kiwi.jpg'
|
|
||||||
YELLOW = (1, .7, 0)
|
|
||||||
ORANGE = (1, .45, 0)
|
|
||||||
RED = (1, 0, 0)
|
|
||||||
WHITE = (1, 1, 1)
|
|
||||||
|
|
||||||
|
|
||||||
class RoundedRectangleWidget(Widget):
|
|
||||||
def prepare(self):
|
|
||||||
with self.canvas:
|
|
||||||
Color(*WHITE)
|
|
||||||
|
|
||||||
# Rectangle of default size 100x100
|
|
||||||
Rectangle(pos=(50, 400))
|
|
||||||
|
|
||||||
# RoundedRectangles of default size 100x100:
|
|
||||||
|
|
||||||
# Textured:
|
|
||||||
RoundedRectangle(
|
|
||||||
pos=(175, 400), radius=[0, 50, 0, 50], source=TEXTURE)
|
|
||||||
|
|
||||||
# Colored:
|
|
||||||
Color(*YELLOW)
|
|
||||||
RoundedRectangle(pos=(300, 400), radius=[0, 50, 0, 50])
|
|
||||||
|
|
||||||
# Textured + Colored
|
|
||||||
# Color(.3,.3,.3, 1)
|
|
||||||
RoundedRectangle(
|
|
||||||
pos=(425, 400), radius=[0, 50, 0, 50], source=TEXTURE)
|
|
||||||
|
|
||||||
# Possible radius arguments:
|
|
||||||
# 1) Same value for each corner
|
|
||||||
Color(*ORANGE)
|
|
||||||
|
|
||||||
# With same radius 20x20
|
|
||||||
RoundedRectangle(pos=(50, 275), radius=[20])
|
|
||||||
|
|
||||||
# With same radius dimensions 20x40
|
|
||||||
RoundedRectangle(pos=(175, 275), radius=[(20, 40)])
|
|
||||||
|
|
||||||
# 2) Different values for each corner
|
|
||||||
Color(*RED)
|
|
||||||
|
|
||||||
# With different radiuses NxN:
|
|
||||||
RoundedRectangle(pos=(300, 275), radius=[10, 20, 30, 40])
|
|
||||||
|
|
||||||
# With different radiuses:
|
|
||||||
RoundedRectangle(
|
|
||||||
pos=(425, 275),
|
|
||||||
radius=[(10, 20), (20, 30), (30, 40), (40, 50)])
|
|
||||||
|
|
||||||
# Default ellipses
|
|
||||||
Color(*WHITE)
|
|
||||||
Ellipse(pos=(50, 150))
|
|
||||||
Ellipse(pos=(175, 150))
|
|
||||||
Ellipse(pos=(300, 150))
|
|
||||||
Ellipse(pos=(425, 150))
|
|
||||||
|
|
||||||
# Radius dimensions can't be bigger than half of the figure side
|
|
||||||
RoundedRectangle(pos=(175, 150), radius=[9000], source=TEXTURE)
|
|
||||||
|
|
||||||
# Segments parameter defines how many segments each corner has.
|
|
||||||
# More segments - more roundness
|
|
||||||
Color(*RED)
|
|
||||||
RoundedRectangle(pos=(300, 150), radius=[9000])
|
|
||||||
RoundedRectangle(pos=(425, 150), radius=[9000], segments=15)
|
|
||||||
|
|
||||||
Color(*ORANGE)
|
|
||||||
RoundedRectangle(pos=(425, 150), radius=[9000], segments=2)
|
|
||||||
|
|
||||||
Color(*YELLOW)
|
|
||||||
RoundedRectangle(pos=(425, 150), radius=[9000], segments=1)
|
|
||||||
|
|
||||||
# Various sizes
|
|
||||||
# You can cut corners by setting segments to 1.
|
|
||||||
# You can set different segment count to corners,
|
|
||||||
# by using a list useful for lowering vertex count
|
|
||||||
# by using small amount on small corners, while using
|
|
||||||
# bigger amount on bigger corners.
|
|
||||||
RoundedRectangle(
|
|
||||||
pos=(50, 25),
|
|
||||||
radius=[40],
|
|
||||||
segments=[1, 1, 10, 10],
|
|
||||||
size=(125, 100))
|
|
||||||
|
|
||||||
# If radius dimension is 0, then the corner will be sharp
|
|
||||||
# (90 degrees). It is also possible to mix tuple values
|
|
||||||
# with numeric
|
|
||||||
Color(*ORANGE)
|
|
||||||
RoundedRectangle(
|
|
||||||
pos=(200, 25),
|
|
||||||
radius=[(40, 20),
|
|
||||||
45.5, 45.5, 0],
|
|
||||||
segments=[2, 3, 3, 1], size=(125, 100))
|
|
||||||
|
|
||||||
Color(*RED)
|
|
||||||
RoundedRectangle(
|
|
||||||
pos=(350, 25),
|
|
||||||
radius=[(40, 40), (40, 40), (20, 20), (20, 20)],
|
|
||||||
segments=[2, 3, 3, 2],
|
|
||||||
size=(150, 100))
|
|
||||||
|
|
||||||
|
|
||||||
class DrawRoundedRectanglesApp(App):
|
|
||||||
def build(self):
|
|
||||||
kv = '''
|
|
||||||
Widget:
|
|
||||||
canvas:
|
|
||||||
Color:
|
|
||||||
rgba: 1, 1,1, 1
|
|
||||||
|
|
||||||
RoundedRectangle:
|
|
||||||
pos: 575, 400
|
|
||||||
size: 100, 100
|
|
||||||
radius: [0, 50, 0, 50]
|
|
||||||
source: 'kiwi.jpg'
|
|
||||||
|
|
||||||
Color:
|
|
||||||
rgba: 0, 0.8, 0.8, 1
|
|
||||||
|
|
||||||
RoundedRectangle:
|
|
||||||
pos: 575, 275
|
|
||||||
size: 100, 100
|
|
||||||
radius: [(10, 20), (20, 30), (30, 40), (40, 50)]
|
|
||||||
|
|
||||||
RoundedRectangle:
|
|
||||||
pos: 575, 150
|
|
||||||
size: 100, 100
|
|
||||||
radius: [9000]
|
|
||||||
segments: 15
|
|
||||||
|
|
||||||
RoundedRectangle:
|
|
||||||
pos: 550, 25
|
|
||||||
size: 150, 100
|
|
||||||
segments: [1, 2, 1, 3]
|
|
||||||
radius: [30, 40, 30, 40]
|
|
||||||
|
|
||||||
'''
|
|
||||||
widget = RoundedRectangleWidget()
|
|
||||||
widget.prepare()
|
|
||||||
kvrect = Builder.load_string(kv)
|
|
||||||
widget.add_widget(kvrect)
|
|
||||||
return widget
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
DrawRoundedRectanglesApp().run()
|
|
@ -1,37 +0,0 @@
|
|||||||
'''
|
|
||||||
Scaling Example
|
|
||||||
================
|
|
||||||
|
|
||||||
This example scales a button using PushMatrix and PopMatrix. It shows
|
|
||||||
a static button with the words 'hello world', stretched about its centre by
|
|
||||||
a factor of 1.5 horizontally and 5 vertically.
|
|
||||||
'''
|
|
||||||
|
|
||||||
|
|
||||||
from kivy.app import App
|
|
||||||
from kivy.lang import Builder
|
|
||||||
|
|
||||||
kv = '''
|
|
||||||
FloatLayout:
|
|
||||||
|
|
||||||
Button:
|
|
||||||
text: 'hello world'
|
|
||||||
size_hint: None, None
|
|
||||||
pos_hint: {'center_x': .5, 'center_y': .5}
|
|
||||||
canvas.before:
|
|
||||||
PushMatrix
|
|
||||||
Scale:
|
|
||||||
x: 1.5
|
|
||||||
y: 5
|
|
||||||
origin: self.center
|
|
||||||
canvas.after:
|
|
||||||
PopMatrix
|
|
||||||
'''
|
|
||||||
|
|
||||||
|
|
||||||
class ScalingApp(App):
|
|
||||||
def build(self):
|
|
||||||
return Builder.load_string(kv)
|
|
||||||
|
|
||||||
|
|
||||||
ScalingApp().run()
|
|
@ -1,85 +0,0 @@
|
|||||||
'''
|
|
||||||
Stencil demo
|
|
||||||
============
|
|
||||||
|
|
||||||
This is a test of the stencil graphics instruction inside the stencil view
|
|
||||||
widget. When you use a stencil, nothing will be drawn outside the bounding
|
|
||||||
box. All the graphics will draw only in the stencil view.
|
|
||||||
|
|
||||||
You can "draw" a stencil view by touch & draw. The touch down will set the
|
|
||||||
position, and the drag will set the size.
|
|
||||||
'''
|
|
||||||
|
|
||||||
from kivy.app import App
|
|
||||||
from kivy.core.window import Window
|
|
||||||
from kivy.graphics import Color, Rectangle
|
|
||||||
from kivy.uix.boxlayout import BoxLayout
|
|
||||||
from kivy.uix.floatlayout import FloatLayout
|
|
||||||
from kivy.uix.button import Button
|
|
||||||
from kivy.uix.label import Label
|
|
||||||
from kivy.uix.stencilview import StencilView
|
|
||||||
from random import random as r
|
|
||||||
from functools import partial
|
|
||||||
|
|
||||||
|
|
||||||
class StencilTestWidget(StencilView):
|
|
||||||
'''Drag to define stencil area
|
|
||||||
'''
|
|
||||||
|
|
||||||
def on_touch_down(self, touch):
|
|
||||||
self.pos = touch.pos
|
|
||||||
self.size = (1, 1)
|
|
||||||
|
|
||||||
def on_touch_move(self, touch):
|
|
||||||
self.size = (touch.x - touch.ox, touch.y - touch.oy)
|
|
||||||
|
|
||||||
|
|
||||||
class StencilCanvasApp(App):
|
|
||||||
|
|
||||||
def add_rects(self, label, wid, count, *largs):
|
|
||||||
label.text = str(int(label.text) + count)
|
|
||||||
with wid.canvas:
|
|
||||||
for x in range(count):
|
|
||||||
Color(r(), 1, 1, mode='hsv')
|
|
||||||
Rectangle(pos=(r() * wid.width + wid.x,
|
|
||||||
r() * wid.height + wid.y), size=(10, 10))
|
|
||||||
|
|
||||||
def reset_stencil(self, wid, *largs):
|
|
||||||
wid.pos = (0, 0)
|
|
||||||
wid.size = Window.size
|
|
||||||
|
|
||||||
def reset_rects(self, label, wid, *largs):
|
|
||||||
label.text = '0'
|
|
||||||
wid.canvas.clear()
|
|
||||||
|
|
||||||
def build(self):
|
|
||||||
wid = StencilTestWidget(size_hint=(None, None), size=Window.size)
|
|
||||||
|
|
||||||
label = Label(text='0')
|
|
||||||
|
|
||||||
btn_add500 = Button(text='+ 200 rects')
|
|
||||||
btn_add500.bind(on_press=partial(self.add_rects, label, wid, 200))
|
|
||||||
|
|
||||||
btn_reset = Button(text='Reset Rectangles')
|
|
||||||
btn_reset.bind(on_press=partial(self.reset_rects, label, wid))
|
|
||||||
|
|
||||||
btn_stencil = Button(text='Reset Stencil')
|
|
||||||
btn_stencil.bind(on_press=partial(self.reset_stencil, wid))
|
|
||||||
|
|
||||||
layout = BoxLayout(size_hint=(1, None), height=50)
|
|
||||||
layout.add_widget(btn_add500)
|
|
||||||
layout.add_widget(btn_reset)
|
|
||||||
layout.add_widget(btn_stencil)
|
|
||||||
layout.add_widget(label)
|
|
||||||
|
|
||||||
root = BoxLayout(orientation='vertical')
|
|
||||||
rfl = FloatLayout()
|
|
||||||
rfl.add_widget(wid)
|
|
||||||
root.add_widget(rfl)
|
|
||||||
root.add_widget(layout)
|
|
||||||
|
|
||||||
return root
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
StencilCanvasApp().run()
|
|
@ -1,146 +0,0 @@
|
|||||||
'''
|
|
||||||
Tesselate Demonstration
|
|
||||||
=======================
|
|
||||||
|
|
||||||
This demonstrates the experimental library for tesselating polygons. You
|
|
||||||
should see a hollow square with some buttons below it. You can click and
|
|
||||||
drag to create additional shapes, watching the number of vertexes and elements
|
|
||||||
at the top of the screen. The 'debug' button toggles showing the mesh in
|
|
||||||
different colors.
|
|
||||||
'''
|
|
||||||
|
|
||||||
|
|
||||||
from kivy.app import App
|
|
||||||
from kivy.graphics import Mesh, Color
|
|
||||||
from kivy.graphics.tesselator import Tesselator, WINDING_ODD, TYPE_POLYGONS
|
|
||||||
from kivy.uix.floatlayout import FloatLayout
|
|
||||||
from kivy.lang import Builder
|
|
||||||
from kivy.logger import Logger
|
|
||||||
|
|
||||||
Builder.load_string("""
|
|
||||||
<ShapeBuilder>:
|
|
||||||
BoxLayout:
|
|
||||||
size_hint_y: None
|
|
||||||
height: "48dp"
|
|
||||||
spacing: "2dp"
|
|
||||||
padding: "2dp"
|
|
||||||
|
|
||||||
ToggleButton:
|
|
||||||
text: "Debug"
|
|
||||||
id: debug
|
|
||||||
on_release: root.build()
|
|
||||||
Button:
|
|
||||||
text: "New shape"
|
|
||||||
on_release: root.push_shape()
|
|
||||||
Button:
|
|
||||||
text: "Build"
|
|
||||||
on_release: root.build()
|
|
||||||
Button:
|
|
||||||
text: "Reset"
|
|
||||||
on_release: root.reset()
|
|
||||||
|
|
||||||
BoxLayout:
|
|
||||||
size_hint_y: None
|
|
||||||
height: "48dp"
|
|
||||||
top: root.top
|
|
||||||
spacing: "2dp"
|
|
||||||
padding: "2dp"
|
|
||||||
Label:
|
|
||||||
id: status
|
|
||||||
text: "Status"
|
|
||||||
""")
|
|
||||||
|
|
||||||
|
|
||||||
class ShapeBuilder(FloatLayout):
|
|
||||||
def __init__(self, **kwargs):
|
|
||||||
super(ShapeBuilder, self).__init__(**kwargs)
|
|
||||||
self.shapes = [
|
|
||||||
[100, 100, 300, 100, 300, 300, 100, 300],
|
|
||||||
[150, 150, 250, 150, 250, 250, 150, 250]
|
|
||||||
] # the 'hollow square' shape
|
|
||||||
self.shape = []
|
|
||||||
self.build()
|
|
||||||
|
|
||||||
def on_touch_down(self, touch):
|
|
||||||
if super(ShapeBuilder, self).on_touch_down(touch):
|
|
||||||
return True
|
|
||||||
Logger.info('tesselate: on_touch_down (%5.2f, %5.2f)' % touch.pos)
|
|
||||||
self.shape.extend(touch.pos)
|
|
||||||
self.build()
|
|
||||||
return True
|
|
||||||
|
|
||||||
def on_touch_move(self, touch):
|
|
||||||
if super(ShapeBuilder, self).on_touch_move(touch):
|
|
||||||
return True
|
|
||||||
Logger.info('tesselate: on_touch_move (%5.2f, %5.2f)' % touch.pos)
|
|
||||||
self.shape.extend(touch.pos)
|
|
||||||
self.build()
|
|
||||||
return True
|
|
||||||
|
|
||||||
def on_touch_up(self, touch):
|
|
||||||
if super(ShapeBuilder, self).on_touch_up(touch):
|
|
||||||
return True
|
|
||||||
Logger.info('tesselate: on_touch_up (%5.2f, %5.2f)' % touch.pos)
|
|
||||||
self.push_shape()
|
|
||||||
self.build()
|
|
||||||
|
|
||||||
def push_shape(self):
|
|
||||||
self.shapes.append(self.shape)
|
|
||||||
self.shape = []
|
|
||||||
|
|
||||||
def build(self):
|
|
||||||
tess = Tesselator()
|
|
||||||
count = 0
|
|
||||||
for shape in self.shapes:
|
|
||||||
if len(shape) >= 3:
|
|
||||||
tess.add_contour(shape)
|
|
||||||
count += 1
|
|
||||||
if self.shape and len(self.shape) >= 3:
|
|
||||||
tess.add_contour(self.shape)
|
|
||||||
count += 1
|
|
||||||
if not count:
|
|
||||||
return
|
|
||||||
ret = tess.tesselate(WINDING_ODD, TYPE_POLYGONS)
|
|
||||||
Logger.info('tesselate: build: tess.tesselate returns {}'.format(ret))
|
|
||||||
self.canvas.after.clear()
|
|
||||||
|
|
||||||
debug = self.ids.debug.state == "down"
|
|
||||||
if debug:
|
|
||||||
with self.canvas.after:
|
|
||||||
c = 0
|
|
||||||
for vertices, indices in tess.meshes:
|
|
||||||
Color(c, 1, 1, mode="hsv")
|
|
||||||
c += 0.3
|
|
||||||
indices = [0]
|
|
||||||
for i in range(1, len(vertices) // 4):
|
|
||||||
if i > 0:
|
|
||||||
indices.append(i)
|
|
||||||
indices.append(i)
|
|
||||||
indices.append(0)
|
|
||||||
indices.append(i)
|
|
||||||
indices.pop(-1)
|
|
||||||
Mesh(vertices=vertices, indices=indices, mode="lines")
|
|
||||||
else:
|
|
||||||
with self.canvas.after:
|
|
||||||
Color(1, 1, 1, 1)
|
|
||||||
for vertices, indices in tess.meshes:
|
|
||||||
Mesh(vertices=vertices, indices=indices,
|
|
||||||
mode="triangle_fan")
|
|
||||||
|
|
||||||
self.ids.status.text = "Shapes: {} - Vertex: {} - Elements: {}".format(
|
|
||||||
count, tess.vertex_count, tess.element_count)
|
|
||||||
|
|
||||||
def reset(self):
|
|
||||||
self.shapes = []
|
|
||||||
self.shape = []
|
|
||||||
self.ids.status.text = "Shapes: {} - Vertex: {} - Elements: {}".format(
|
|
||||||
0, 0, 0)
|
|
||||||
self.canvas.after.clear()
|
|
||||||
|
|
||||||
|
|
||||||
class TessApp(App):
|
|
||||||
def build(self):
|
|
||||||
return ShapeBuilder()
|
|
||||||
|
|
||||||
|
|
||||||
TessApp().run()
|
|
@ -1,143 +0,0 @@
|
|||||||
'''
|
|
||||||
Texture Wrapping and Coordinates Example
|
|
||||||
========================================
|
|
||||||
|
|
||||||
This example changes texture properties and the properties
|
|
||||||
of its containing rectangle. You should see some a multicolored
|
|
||||||
texture with sliders to the left and below and buttons at the
|
|
||||||
bottom of the screen. The image texture_example_image.png is
|
|
||||||
rendered into the rectangle. Sliders change the number of copies of the
|
|
||||||
texture (the tex_coords), the size of enclosing rectangle (the taw_height
|
|
||||||
and taw_width) while the buttons change how the texture is rendered when more
|
|
||||||
than one copy is in the rectangle (the
|
|
||||||
texture_wrap).
|
|
||||||
|
|
||||||
'''
|
|
||||||
|
|
||||||
|
|
||||||
from kivy.uix.widget import Widget
|
|
||||||
from kivy.properties import ObjectProperty, ListProperty, StringProperty
|
|
||||||
from kivy.lang import Builder
|
|
||||||
from kivy.clock import Clock
|
|
||||||
from kivy.base import runTouchApp
|
|
||||||
|
|
||||||
|
|
||||||
class TextureAccessibleWidget(Widget):
|
|
||||||
texture = ObjectProperty(None)
|
|
||||||
tex_coords = ListProperty([0, 0, 1, 0, 1, 1, 0, 1])
|
|
||||||
texture_wrap = StringProperty('clamp_to_edge')
|
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
|
||||||
super(TextureAccessibleWidget, self).__init__(**kwargs)
|
|
||||||
Clock.schedule_once(self.texture_init, 0)
|
|
||||||
|
|
||||||
def texture_init(self, *args):
|
|
||||||
self.texture = self.canvas.children[-1].texture
|
|
||||||
|
|
||||||
def on_texture_wrap(self, instance, value):
|
|
||||||
self.texture.wrap = value
|
|
||||||
|
|
||||||
|
|
||||||
root = Builder.load_string('''
|
|
||||||
<TextureAccessibleWidget>:
|
|
||||||
canvas:
|
|
||||||
Rectangle:
|
|
||||||
pos: self.pos
|
|
||||||
size: self.size
|
|
||||||
source: 'texture_example_image.png'
|
|
||||||
tex_coords: root.tex_coords
|
|
||||||
|
|
||||||
<SliderWithValue@BoxLayout>:
|
|
||||||
min: 0.0
|
|
||||||
max: 1.0
|
|
||||||
value: slider.value
|
|
||||||
Slider:
|
|
||||||
id: slider
|
|
||||||
orientation: root.orientation
|
|
||||||
min: root.min
|
|
||||||
max: root.max
|
|
||||||
value: 1.0
|
|
||||||
Label:
|
|
||||||
size_hint: None, None
|
|
||||||
size: min(root.size), min(root.size)
|
|
||||||
text: str(slider.value)[:4]
|
|
||||||
|
|
||||||
BoxLayout:
|
|
||||||
orientation: 'vertical'
|
|
||||||
BoxLayout:
|
|
||||||
SliderWithValue:
|
|
||||||
orientation: 'vertical'
|
|
||||||
size_hint_x: None
|
|
||||||
width: dp(40)
|
|
||||||
min: 0
|
|
||||||
max: 5
|
|
||||||
value: 1
|
|
||||||
on_value: taw.tex_coords[5] = self.value
|
|
||||||
on_value: taw.tex_coords[7] = self.value
|
|
||||||
SliderWithValue:
|
|
||||||
orientation: 'vertical'
|
|
||||||
size_hint_x: None
|
|
||||||
width: dp(40)
|
|
||||||
min: 0
|
|
||||||
max: taw_container.height
|
|
||||||
value: 0.5*taw_container.height
|
|
||||||
on_value: taw.height = self.value
|
|
||||||
AnchorLayout:
|
|
||||||
id: taw_container
|
|
||||||
anchor_x: 'left'
|
|
||||||
anchor_y: 'bottom'
|
|
||||||
TextureAccessibleWidget:
|
|
||||||
id: taw
|
|
||||||
size_hint: None, None
|
|
||||||
BoxLayout:
|
|
||||||
size_hint_y: None
|
|
||||||
height: dp(80)
|
|
||||||
BoxLayout:
|
|
||||||
orientation: 'vertical'
|
|
||||||
size_hint_x: None
|
|
||||||
width: dp(80)
|
|
||||||
Label:
|
|
||||||
text: 'size'
|
|
||||||
text_size: self.size
|
|
||||||
halign: 'right'
|
|
||||||
valign: 'middle'
|
|
||||||
Label:
|
|
||||||
text: 'tex_coords'
|
|
||||||
text_size: self.size
|
|
||||||
halign: 'left'
|
|
||||||
valign: 'middle'
|
|
||||||
BoxLayout:
|
|
||||||
orientation: 'vertical'
|
|
||||||
SliderWithValue:
|
|
||||||
min: 0
|
|
||||||
max: taw_container.width
|
|
||||||
value: 0.5*taw_container.width
|
|
||||||
on_value: taw.width = self.value
|
|
||||||
SliderWithValue:
|
|
||||||
min: 0.
|
|
||||||
max: 5.
|
|
||||||
value: 1.
|
|
||||||
on_value: taw.tex_coords[2] = self.value
|
|
||||||
on_value: taw.tex_coords[4] = self.value
|
|
||||||
|
|
||||||
BoxLayout:
|
|
||||||
size_hint_y: None
|
|
||||||
height: dp(50)
|
|
||||||
Label:
|
|
||||||
text: 'texture wrap:'
|
|
||||||
text_size: self.size
|
|
||||||
valign: 'middle'
|
|
||||||
halign: 'center'
|
|
||||||
Button:
|
|
||||||
text: 'clamp_to_edge'
|
|
||||||
on_press: taw.texture_wrap = 'clamp_to_edge'
|
|
||||||
Button:
|
|
||||||
text: 'repeat'
|
|
||||||
on_press: taw.texture_wrap = 'repeat'
|
|
||||||
Button:
|
|
||||||
text: 'mirrored_repeat'
|
|
||||||
on_press: taw.texture_wrap = 'mirrored_repeat'
|
|
||||||
''')
|
|
||||||
|
|
||||||
|
|
||||||
runTouchApp(root)
|
|
Before Width: | Height: | Size: 5.3 KiB |
@ -1,28 +0,0 @@
|
|||||||
#:kivy 1.8.0
|
|
||||||
#:import datetime datetime
|
|
||||||
|
|
||||||
RootWidget:
|
|
||||||
# import container
|
|
||||||
container: container
|
|
||||||
|
|
||||||
# fill the container
|
|
||||||
BoxLayout:
|
|
||||||
id: container
|
|
||||||
orientation: 'vertical'
|
|
||||||
padding: 0
|
|
||||||
spacing: 3
|
|
||||||
|
|
||||||
Label:
|
|
||||||
text: 'screen-1'
|
|
||||||
|
|
||||||
BoxLayout:
|
|
||||||
orientation: 'horizontal'
|
|
||||||
padding: 0
|
|
||||||
spacing: 1
|
|
||||||
size_hint: 1, 0.1
|
|
||||||
|
|
||||||
# weiter button
|
|
||||||
Button:
|
|
||||||
size_hint: 0.2, 1
|
|
||||||
text: 'next'
|
|
||||||
on_release: app.next_screen('2')
|
|
@ -1,28 +0,0 @@
|
|||||||
#:kivy 1.8.0
|
|
||||||
#:import datetime datetime
|
|
||||||
|
|
||||||
RootWidget:
|
|
||||||
# import container
|
|
||||||
container: container
|
|
||||||
|
|
||||||
# fill the container
|
|
||||||
BoxLayout:
|
|
||||||
id: container
|
|
||||||
orientation: 'vertical'
|
|
||||||
padding: 0
|
|
||||||
spacing: 3
|
|
||||||
|
|
||||||
Label:
|
|
||||||
text: 'screen-2'
|
|
||||||
|
|
||||||
BoxLayout:
|
|
||||||
orientation: 'horizontal'
|
|
||||||
padding: 0
|
|
||||||
spacing: 1
|
|
||||||
size_hint: 1, 0.1
|
|
||||||
|
|
||||||
# weiter button
|
|
||||||
Button:
|
|
||||||
size_hint: 0.2, 1
|
|
||||||
text: 'next'
|
|
||||||
on_release: app.next_screen('3')
|
|