commiting in case the kivy trial fails
@ -3,3 +3,7 @@
|
||||
This will be where we keep the code for the web-based-client.
|
||||
This client comms with our server code base found under `/server/` in this repository.
|
||||
|
||||
## Client Config Description
|
||||
|
||||
For unix based systems configuration will be found at `$HOME/.config/freechat-client/config.json`.
|
||||
There a few top levle items that I will describe here.
|
||||
|
76
freechat-client/share/kivy-examples/3Drendering/main.py
Normal file
@ -0,0 +1,76 @@
|
||||
'''
|
||||
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()
|
7966
freechat-client/share/kivy-examples/3Drendering/monkey.obj
Normal file
147
freechat-client/share/kivy-examples/3Drendering/objloader.py
Normal file
@ -0,0 +1,147 @@
|
||||
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
|
47
freechat-client/share/kivy-examples/3Drendering/simple.glsl
Normal file
@ -0,0 +1,47 @@
|
||||
/* 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);
|
||||
}
|
72
freechat-client/share/kivy-examples/RST_Editor/editor.kv
Normal file
@ -0,0 +1,72 @@
|
||||
#: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)
|
||||
|
64
freechat-client/share/kivy-examples/RST_Editor/main.py
Normal file
@ -0,0 +1,64 @@
|
||||
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()
|
@ -0,0 +1,3 @@
|
||||
title=Compass
|
||||
author=Nik Klever
|
||||
orientation=portrait
|
@ -0,0 +1,25 @@
|
||||
#: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
|
77
freechat-client/share/kivy-examples/android/compass/main.py
Normal file
@ -0,0 +1,77 @@
|
||||
'''
|
||||
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()
|
BIN
freechat-client/share/kivy-examples/android/compass/needle.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
freechat-client/share/kivy-examples/android/compass/rose.png
Normal file
After Width: | Height: | Size: 31 KiB |
@ -0,0 +1,3 @@
|
||||
title=TakePicture
|
||||
author=Mathieu Virbel
|
||||
orientation=portrait
|
@ -0,0 +1,80 @@
|
||||
'''
|
||||
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()
|
After Width: | Height: | Size: 3.5 KiB |
@ -0,0 +1,40 @@
|
||||
#: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)
|
||||
|
||||
|
||||
|
42
freechat-client/share/kivy-examples/animation/animate.py
Normal file
@ -0,0 +1,42 @@
|
||||
'''
|
||||
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()
|
152
freechat-client/share/kivy-examples/application/app_suite.py
Normal file
@ -0,0 +1,152 @@
|
||||
'''
|
||||
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.")
|
@ -0,0 +1,4 @@
|
||||
#:kivy 1.0
|
||||
|
||||
Button:
|
||||
text: 'Hello from app_suite_data/testkvdir.kv'
|
@ -0,0 +1,24 @@
|
||||
'''
|
||||
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()
|
@ -0,0 +1,49 @@
|
||||
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()
|
@ -0,0 +1,25 @@
|
||||
'''
|
||||
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()
|
@ -0,0 +1,27 @@
|
||||
'''
|
||||
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()
|
@ -0,0 +1,4 @@
|
||||
#:kivy 1.0
|
||||
|
||||
Button:
|
||||
text: 'Hello from template1/test.kv'
|
4
freechat-client/share/kivy-examples/application/test.kv
Normal file
@ -0,0 +1,4 @@
|
||||
#:kivy 1.0
|
||||
|
||||
Button:
|
||||
text: 'Hello from test.kv'
|
@ -0,0 +1,4 @@
|
||||
#:kivy 1.0
|
||||
|
||||
Button:
|
||||
text: 'Hello from testkvfile.kv'
|
59
freechat-client/share/kivy-examples/audio/audio.kv
Normal file
@ -0,0 +1,59 @@
|
||||
#: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'
|
81
freechat-client/share/kivy-examples/audio/main.py
Normal file
@ -0,0 +1,81 @@
|
||||
'''
|
||||
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()
|
42
freechat-client/share/kivy-examples/audio/pitch.py
Normal file
@ -0,0 +1,42 @@
|
||||
# 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()
|
59
freechat-client/share/kivy-examples/camera/main.py
Normal file
@ -0,0 +1,59 @@
|
||||
'''
|
||||
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()
|
105
freechat-client/share/kivy-examples/canvas/bezier.py
Normal file
@ -0,0 +1,105 @@
|
||||
'''
|
||||
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()
|
72
freechat-client/share/kivy-examples/canvas/canvas_stress.py
Normal file
@ -0,0 +1,72 @@
|
||||
'''
|
||||
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()
|
84
freechat-client/share/kivy-examples/canvas/circle.py
Normal file
@ -0,0 +1,84 @@
|
||||
'''
|
||||
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()
|
91
freechat-client/share/kivy-examples/canvas/fbo_canvas.py
Normal file
@ -0,0 +1,91 @@
|
||||
'''
|
||||
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()
|
BIN
freechat-client/share/kivy-examples/canvas/kiwi.jpg
Normal file
After Width: | Height: | Size: 13 KiB |
296
freechat-client/share/kivy-examples/canvas/lines.py
Normal file
@ -0,0 +1,296 @@
|
||||
'''
|
||||
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()
|
183
freechat-client/share/kivy-examples/canvas/lines_extended.py
Normal file
@ -0,0 +1,183 @@
|
||||
'''
|
||||
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()
|
57
freechat-client/share/kivy-examples/canvas/mesh.py
Normal file
@ -0,0 +1,57 @@
|
||||
'''
|
||||
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()
|
101
freechat-client/share/kivy-examples/canvas/mesh_manipulation.py
Normal file
@ -0,0 +1,101 @@
|
||||
'''
|
||||
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()
|
BIN
freechat-client/share/kivy-examples/canvas/mtexture1.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
freechat-client/share/kivy-examples/canvas/mtexture2.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
110
freechat-client/share/kivy-examples/canvas/multitexture.py
Normal file
@ -0,0 +1,110 @@
|
||||
'''
|
||||
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()
|
65
freechat-client/share/kivy-examples/canvas/repeat_texture.py
Normal file
@ -0,0 +1,65 @@
|
||||
'''
|
||||
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()
|
35
freechat-client/share/kivy-examples/canvas/rotation.py
Normal file
@ -0,0 +1,35 @@
|
||||
'''
|
||||
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()
|
153
freechat-client/share/kivy-examples/canvas/rounded_rectangle.py
Normal file
@ -0,0 +1,153 @@
|
||||
# -*- 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()
|
37
freechat-client/share/kivy-examples/canvas/scale.py
Normal file
@ -0,0 +1,37 @@
|
||||
'''
|
||||
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()
|
85
freechat-client/share/kivy-examples/canvas/stencil_canvas.py
Normal file
@ -0,0 +1,85 @@
|
||||
'''
|
||||
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()
|
146
freechat-client/share/kivy-examples/canvas/tesselate.py
Normal file
@ -0,0 +1,146 @@
|
||||
'''
|
||||
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()
|
143
freechat-client/share/kivy-examples/canvas/texture.py
Normal file
@ -0,0 +1,143 @@
|
||||
'''
|
||||
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)
|
After Width: | Height: | Size: 5.3 KiB |
28
freechat-client/share/kivy-examples/container/kv/1.kv
Normal file
@ -0,0 +1,28 @@
|
||||
#: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')
|