Merge branch 'master' of ssh://github.com/kivy/kivy

This commit is contained in:
Mathieu Virbel 2013-03-19 22:29:56 -07:00
commit efb19db1aa
7 changed files with 234 additions and 64 deletions

View File

@ -12,8 +12,8 @@ this section explains the basic ideas of the implementation in more detail.
You can skip this section and refer to it later, but we suggest at least
skimming it for a rough overview.
Kivy consists of several building blocks that we will explain in the
following.
Kivy consists of several building blocks that we will explain shortly. Here is a
graphical summary of the architecture:
.. image:: ../images/architecture.png
:align: center
@ -23,14 +23,13 @@ following.
Core Providers and Input Providers
----------------------------------
One idea that is key to understanding Kivy internals is that of modularity and
abstraction. We try to abstract from basic tasks such as opening a window,
One idea that is key to understanding Kivy's internals is that of modularity and
abstraction. We try to abstract basic tasks such as opening a window,
displaying images and text, playing audio, getting images from a camera,
spelling correction and so on. We call these *core* tasks. This makes the API
both easy to use and easy to extend. Most importantly, it allows us to use
-- what we call -- specific providers for the respective scenario in which
your app is being run.
spelling correction and so on. We call these *core* tasks.
This makes the API both easy to use and easy to extend. Most importantly, it
allows us to use -- what we call -- specific providers for the respective
scenarios in which your app is being run.
For example, on OSX, Linux and Windows, there are different native APIs for the
different core tasks. A piece of code that uses one of these specific APIs to
talk to the operating system on one side and to Kivy on the other (acting as an
@ -39,8 +38,8 @@ The advantage of using specialized core providers for each platform is that we
can fully leverage the functionality exposed by the operating system and act as
efficiently as possible. It also gives users a choice. Furthermore, by using
libraries that are shipped with any one platform, we effectively reduce the size
of the Kivy distribution and make packaging easier. It's also easier to port
Kivy to other platforms. The Android port did greatly benefit from this.
of the Kivy distribution and make packaging easier. This also makes it easier to port
Kivy to other platforms. The Android port benefited greatly from this.
We follow the same concept with input handling. *An input provider* is a piece
of code that adds support for a specific input device, such as Apple's
@ -68,7 +67,7 @@ optimize the drawing commands that your code issues. This is especially
helpful if you're not an expert at tuning OpenGL. This makes your drawing
code more efficient in many cases.
You can, of course, still use raw OpenGL commands if you prefer that. The
You can, of course, still use raw OpenGL commands if you prefer. The
version we target is OpenGL 2.0 ES (GLES2) on all devices, so if you want to
stay cross-platform compatible, we advise you to only use the GLES2 functions.
@ -97,7 +96,7 @@ The code in the core package provides commonly used features, such as:
Properties
These are not the normal properties that you may know from python.
It is our own properties class that links your widget code with
They are our own property classes that link your widget code with
the user interface description.
@ -138,7 +137,7 @@ You can also write your own modules.
Input Events (Touches)
----------------------
Kivy abstracts from different input types and sources such as touches, mice,
Kivy abstracts different input types and sources such as touches, mice,
TUIO or similar. What all of these input types have in common is that you
can associate a 2D onscreen-position with any individual input event. (There are
other input devices such as accelerometers where you cannot easily find a
@ -175,7 +174,7 @@ Widgets and Event Dispatching
The term *widget* is often used in GUI programming contexts to describe
some part of the program that the user interacts with.
For Kivy, a widget is an object that receives input events. It does not
In Kivy, a widget is an object that receives input events. It does not
necessarily have to have a visible representation on the screen.
All widgets are arranged in a *widget tree* (which is a tree data structure
as known from computer science classes): One widget can have any number of
@ -192,7 +191,7 @@ corresponding on_touch_down, on_touch_move or on_touch_up event handler
being called.
Each widget (this includes the root widget) in the tree can choose to
either digest or pass the event further. If an event handler returns True
either digest or pass the event on. If an event handler returns True,
it means that the event has been digested and handled properly. No further
processing will happen with that event. Otherwise, the event handler
passes the widget on to its own children by calling its superclass's

View File

@ -4,16 +4,17 @@
Events and Properties
=====================
Events are an important part of kivy programming. That may not be surprising to those
with GUI development experience, but it's an important concept for
newcomers. Once you understand how events work and how to bind to them,
you will see them everywhere in kivy. They make it easy to
build whatever behaviour you want into kivy.
Events are an important part of Kivy programming. That may not be surprising to
those with GUI development experience, but it's an important concept for
newcomers. Once you understand how events work and how to bind to them, you
will see them everywhere in Kivy. They make it easy to build whatever behavior
you want into Kivy.
The following illustration shows how events are handled in the kivy framework.
The following illustration shows how events are handled in the Kivy framework.
.. image:: images/Events.*
Introduction to the Event Dispatcher
------------------------------------
@ -24,6 +25,105 @@ dispatchers). The :class:`~kivy.uix.widget.Widget`,
:class:`~kivy.animation.Animation` and :obj:`~kivy.clock.Clock` classes are
examples of event dispatchers.
As outlined in the Illustration above, Kivy has a `main loop`. It's important
that you avoid breaking it. The main loop is responsible for reading from
inputs, loading images asynchronously, drawing to frame, ...etc. Avoid
long/infinite loops or sleeping. For example the following code does both::
while True:
animate_something()
time.sleep(.10)
When you run this, the program will never exit your loop, preventing Kivy from
doing all of the other things that need doing. As a result, all you'll see is a
black window which you won't be able to interact with. You need to "schedule"
your ``animate_something()`` function call over time. You can do this in 2 ways:
a repetitive call or one-time call.
Scheduling a repetitive event
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can call a function or a method every X times per second using
:meth:`~kivy.clock.Clock.schedule_interval`. Here is an example of calling a
function named my_callback 30 times per second::
def my_callback(dt):
print 'My callback is called', dt
Clock.schedule_interval(my_callback, 1 / 30.)
You have two ways of unscheduling a previously scheduled event. The first would be
to use :meth:`~kivy.clock.Clock.unschedule`::
Clock.unschedule(my_callback)
Or, you can return False in your callback, and your event will be automatically
unscheduled::
count = 0
def my_callback(dt):
global count
count += 1
if count == 10:
print 'Last call of my callback, bye bye !'
return False
print 'My callback is called'
Clock.schedule_interval(my_callback, 1 / 30.)
Scheduling a one-time event
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Using :meth:`~kivy.clock.Clock.schedule_once`, you can call a function "later",
like in the next frame, or in X seconds::
def my_callback(dt):
print 'My callback is called !'
Clock.schedule_once(my_callback, 1)
This will call ``my_calback`` in one second. The second argument is the amount
of time to wait before calling the function, in seconds. However, you can
achieve some other results with special values for the second argument:
- If X is greater than 0, the callback will be called in X seconds
- If X is 0, the callback will be called after the next frame
- If X is -1, the callback will be called before the next frame
The -1 is mostly used when you are already in a scheduled event, and if you
want to schedule a call BEFORE the next frame is happening.
Trigger events
~~~~~~~~~~~~~~
If you want to schedule a function to be called only once for the next frame,
like a trigger, you can achieve that like so::
Clock.unschedule(my_callback)
Clock.schedule_once(my_callback, 0)
This way of programming a trigger is expensive, since you'll always call
unschedule, whether or not you've even scheduled it. In addition, unschedule
needs to iterate the weakref list of the Clock in order to find your callback
and remove it. Use a trigger instead::
trigger = Clock.create_trigger(my_callback)
# later
trigger()
Each time you call trigger, it will schedule a single call of your callback. If
it was already scheduled, it will not be rescheduled.
Widget events
-------------
A widget has 2 types of events:
- Property event: if your widget changes its position or size, an event is fired.
- Widget-defined event: an event will be fired for a Button when it's pressed or
released.
Creating custom events
----------------------
@ -181,7 +281,7 @@ property value is changed.
**Binding to the property**
How to monitor changes to a property when all you have access to is a widget's
How to monitor changes to a property when all you have access to is a widgets
instance? You *bind* to the property::
your_widget_instance.bind(property_name=function_name)
@ -206,7 +306,7 @@ For example, consider the following code:
If you run the code as is, you will notice two print statements in the console.
One from the `on_pressed` event that is called inside the `CustomBtn` class and
one from the `btn_pressed` function that we bind to the property change.
another from the `btn_pressed` function that we bind to the property change.
The reason that both the functions are called is simple. Binding doesn't mean
overriding. Having both of these functions is redundant and you should generally

Binary file not shown.

Before

Width:  |  Height:  |  Size: 286 KiB

After

Width:  |  Height:  |  Size: 105 KiB

View File

@ -272,20 +272,20 @@ Consider the code below::
Instead of having to repeat the same values for every button, we can just use a
template instead, like so::
[Mbut@Button]:
[MyBigButt@Button]:
text: ctx.text if hasattr(ctx, 'text') else ''
text_size: self.size
font_size: '25sp'
markup: True
<MyWidget>:
MButton:
MyBigButt:
text: "Hello world, watch this text wrap inside the button"
MButton:
MyBigButt:
text: "Even absolute is relative to itself"
MButton:
MyBigButt:
text: "repeating the same thing over and over in a comp = fail"
MButton:
MyBigButt:
`ctx` is a keyword inside a template that can be used to access the individual
attributes of each instance of this template.

View File

@ -38,7 +38,7 @@ Widgets
Introduction to Widget
----------------------
A |Widget| can be termed as the base building block of a GUI interface in Kivy.
A |Widget| can be termed as the base building block of GUI interfaces in Kivy.
It provides a |Canvas| that can be used to draw on screen. It receives events
and reacts to them. For a in depth explanation about the |Widget| class,
Look at the module documentation.
@ -46,17 +46,84 @@ Look at the module documentation.
Manipulating the Widget tree
----------------------------
Widgets are organized in Trees, your application has a `root widget`, which
usually has |children| that can have |children| on their own. Children of a
widget are represented as the |children| attribute which is a |ListProperty|.
For adding |children| to a |Widget|, call |add_widget|. Likewise, to remove a
widget, from its parent, call |remove_widget|.
Widgets in kivy like in many other frameworks are organized in Trees, your
application has a `root widget`, which usually has |children| that can have
|children| of their own. Children of a widget are represented as the |children|
attribute which is a |ListProperty|.
The Widget Tree can be manipulated with the following methods:
- :meth:`~kivy.uix.widget.Widget.add_widget`: add a widget as a child
- :meth:`~kivy.uix.widget.Widget.remove_widget`: remove a widget from the
children list
- :meth:`~kivy.uix.widget.Widget.clear_widgets`: remove all children from a
widget
For example, if you want to add a button inside a boxlayout, you can do::
layout = BoxLayout(padding=10)
button = Button(text='My first button')
layout.add_widget(button)
Now, the button parent will be set to layout, and layout will have button in his
children list. To remove the button from the layout::
layout.remove_widget(button)
The button parent will be set to None, and layout will remove button from his
children list.
If you want to clear all the children inside a widget, use
:meth:`~kivy.uix.widget.Widget.clear_widgets` method::
layout.clear_widgets()
.. warning::
Never manipulate the children list yourself, if you don't know what you are
doing. The widget tree is associated to a graphic tree. For example, if you
add a widget into the children list without adding its canvas to the
graphics tree, the widget will be a child yes, but nothing will be drawn
on the screen. More than that, you might have issues on further calls of
add_widget, remove_widget and clear_widgets.
Traversing the tree
-------------------
The widget class has a :data:`~kivy.uix.widget.Widget.children` list property
that contains all the children. You can easily traverse the tree by doing::
root = BoxLayout()
# ... add widgets to root ...
for child in root.children:
print child
However, this must be used carefuly. If you intend to modify the children list
with one of the methods shown in the previous section, you must use a copy of
the list like this::
for child in root.children[:]:
# manipulate the tree. For example here, remove all widgets that have a
# width < 100
if child.width < 100:
root.remove_widget(child)
Widgets don't influence the size/pos of their children by default, so the
|pos| attribute is the absolute position in screen co-ordinates (unless, of
course, you use the |RelativeLayout|, more on that later) and |size|, its
absolute size.
Widgets Z index
---------------
Widgets canvas/graphical representation is drawn based on their position in
the Widget Tree. I.E. The last widgets canvas is drawn last(on top of everything
else inside its parent). Add Widget takes a `index` parameter that you can use like so::
root.add_widget(widget, index)
to try and manipulate the z-index of a child
Organize with Layouts
---------------------
@ -77,7 +144,6 @@ Look at the documentation of the various Layouts to see How they honor
- |AnchorLayout|
|size_hint| is a |ReferenceListProperty| of
|size_hint_x| and |size_hint_y|. It excepts values from `0` to `1` or `None`
and defaults to `(1, 1)`. This signifies that if the widget is in a layout,

View File

@ -437,8 +437,8 @@ cdef class NumericProperty(Property):
cdef check(self, EventDispatcher obj, value):
if Property.check(self, obj, value):
return True
if type(value) not in (int, float):
raise ValueError('%s.%s accept only int/float (got %r)' % (
if type(value) not in (int, float, long):
raise ValueError('%s.%s accept only int/float/long (got %r)' % (
obj.__class__.__name__,
self.name, value))
@ -446,7 +446,7 @@ cdef class NumericProperty(Property):
if x is None:
return x
tp = type(x)
if tp is int or tp is float:
if tp is int or tp is float or tp is long:
return x
if tp is tuple or tp is list:
if len(x) != 2:

View File

@ -1,6 +1,7 @@
;; kivy-mode.el --- Emacs major mode for editing Kivy files
;;; kivy-mode.el --- Emacs major mode for editing Kivy files
;;
;; Author: Dean Serenevy <dean@serenevy.net>
;; Version: 0.1.0
;;
;; This document borrowed heavily from yaml-mode.el by Yoshiki Kurihara and
;; Marshall Vandegrift.
@ -42,7 +43,6 @@
;; (define-key kivy-mode-map "\C-m" 'newline-and-indent)))
;; User definable variables
(defgroup kivy nil
@ -66,8 +66,8 @@
:group 'kivy)
(defface kivy-tab-face
'((((class color)) (:background "red" :foreground "red" :bold t))
(t (:reverse-video t)))
'((((class color)) (:background "red" :foreground "red" :bold t))
(t (:reverse-video t)))
"Face to use for highlighting tabs in kivy files."
:group 'faces
:group 'kivy)
@ -79,7 +79,6 @@
:group 'kivy)
;; Constants
(defconst kivy-mode-version "0.1.0" "Version of `kivy-mode.'")
@ -118,7 +117,7 @@
"Regexp matching certain scalar constants in scalar context")
;; Mode setup
(defvar kivy-mode-map ()
@ -143,6 +142,12 @@
(modify-syntax-entry ?_ "w" kivy-mode-syntax-table)
)
;;;###autoload
(add-to-list 'auto-mode-alist '("\\.kv$" . kivy-mode))
;;;###autoload
(define-derived-mode kivy-mode fundamental-mode "kivy"
"Simple mode to edit kivy.
@ -156,38 +161,36 @@
(font-lock-syntactic-keywords))))
;; Font-lock support
(defvar kivy-font-lock-keywords
(list
(cons kivy-comment-re '(1 font-lock-comment-face))
(cons kivy-constant-scalars-re '(1 font-lock-constant-face))
(cons kivy-tag-re '(1 font-lock-function-name-face))
(cons kivy-hash-key-re '(1 font-lock-variable-name-face t))
(cons kivy-directive-re '(1 font-lock-builtin-face))
'("^[\t]+" 0 'kivy-tab-face t))
"Additional expressions to highlight in kivy mode.")
(list
(cons kivy-comment-re '(1 font-lock-comment-face))
(cons kivy-constant-scalars-re '(1 font-lock-constant-face))
(cons kivy-tag-re '(1 font-lock-function-name-face))
(cons kivy-hash-key-re '(1 font-lock-variable-name-face t))
(cons kivy-directive-re '(1 font-lock-builtin-face))
'("^[\t]+" 0 'kivy-tab-face t))
"Additional expressions to highlight in kivy mode.")
(defvar kivy-font-lock-syntactic-keywords
(list '())
"Additional syntax features to highlight in kivy mode.")
;; Indentation and electric keys
(defun kivy-compute-indentation ()
"Calculate the maximum sensible indentation for the current line."
(save-excursion
(beginning-of-line)
(forward-line -1)
(while (and (looking-at kivy-blank-line-re)
(> (point) (point-min)))
(forward-line -1))
(+ (current-indentation)
(if (looking-at kivy-nested-map-re) kivy-indent-offset 0)
)))
(forward-line -1)
(while (and (looking-at kivy-blank-line-re)
(> (point) (point-min)))
(forward-line -1))
(+ (current-indentation)
(if (looking-at kivy-nested-map-re) kivy-indent-offset 0)
)))
(defun kivy-indent-line ()
"Indent the current line.
@ -205,8 +208,8 @@ back-dent the line by `kivy-indent-offset' spaces. On reaching column
(if (and (equal last-command this-command) (/= ci 0))
(indent-to (* (/ (- ci 1) kivy-indent-offset) kivy-indent-offset))
(indent-to need)))
(if (< (current-column) (current-indentation))
(forward-to-indentation 0))))
(if (< (current-column) (current-indentation))
(forward-to-indentation 0))))
(defun kivy-electric-backspace (arg)
"Delete characters or back-dent the current line.
@ -239,3 +242,5 @@ immediately previous multiple of `kivy-indent-offset' spaces."
kivy-mode-version)
(provide 'kivy-mode)
;;; kivy-mode.el ends here