mirror of https://github.com/kivy/kivy.git
Merge branch 'master' of ssh://github.com/kivy/kivy
This commit is contained in:
commit
efb19db1aa
|
@ -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
|
||||
|
|
|
@ -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 |
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue