Merge remote-tracking branch 'upstream/master' into uix-listview

This commit is contained in:
Jeff Pittman 2012-08-10 05:37:28 -05:00
commit 8ea94003e7
27 changed files with 163 additions and 82 deletions

View File

@ -2,8 +2,7 @@ Kivy - Documentation
====================
You can access the API documentation on web :
* last released version : http://kivy.org/docs/api
* trunk version, updated nightly : http://kivy.org/docs/api-trunk/
* last released version : http://kivy.org/docs/api-index.html
How to build the documentation

View File

@ -249,6 +249,15 @@ Will result in:
`:doc:` and `:mod:` are essentially the same, except for an anchor in the url,
this makes `:doc:` prefered, for the cleaner url.
To build your documentation, run::
make html
If you updated your kivy install, and have some trouble compiling docs, run::
make clean force html
The doc will be generated in ``build/html``.
Unit tests contributions
------------------------

View File

@ -27,8 +27,9 @@ create the UI around the ``Controller`` class in a file named `controller.kv`,
which will be loaded when we run the ``ControllerApp``. How this is done and
what files are loaded is described in the :func:`kivy.app.App.load_kv` method.
.. include:: ../../../examples/guide/designwithkv/controller.kv
:literal:
.. literalinclude:: ../../../examples/guide/designwithkv/controller.kv
:language: kv
:linenos:
One label and one button in a vertical ``BoxLayout``. Seems very simple. There
are 3 things going on here:
@ -52,7 +53,9 @@ are 3 things going on here:
the current widget.
* You can use any id declared in the rule the same as ``root`` and
``self``. For example, you could do this in the ``on_press()``::
``self``. For example, you could do this in the ``on_press()``:
.. code-block:: kv
Button:
on_press: root.do_action(); my_custom_label.font_size = 18

View File

@ -13,13 +13,13 @@ Using Twisted inside Kivy
install a twisted reactor that will run inside the kivy event loop.
Any arguments or keyword arguments passed to this function will be
passed on the the threadedselect reactors interleave function, these
passed on the threadedselect reactors interleave function, these
are the arguments one would usually pass to twisted's reactor.startRunning
.. warning::
Unlike the default twisted reactor, the installed reactor will not handle
any signals unnless you set the 'installSignalHandlers' keyword argument
to 1 explicitly. This is done to allow kivy to handle teh signals as
to 1 explicitly. This is done to allow kivy to handle the signals as
usual, unless you specifically want the twisted reactor to handle the
signals (e.g. SIGINT).
@ -27,14 +27,15 @@ Using Twisted inside Kivy
The kivy examples include a small example for a twisted server and client.
The server app has a simple twisted server running and log any messages.
The client app can send messages to teh server and will print its message
The client app can send messages to the server and will print its message
and the repsonse it got. The examples are based mostly on simple Echo example
from the twisted docs, which you can find here:
- http://twistedmatrix.com/documents/current/core/examples/simpleserv.py
- http://twistedmatrix.com/documents/current/core/examples/simpleclient.py
To try the example run echo_server_app.py first, and then launch
echo_client_app.py. The server will, reply with simple echo messages to
echo_client_app.py. The server will reply with simple echo messages to
anything the client app sends, when you hit enter after typing something
in the textbox.

View File

@ -74,8 +74,9 @@ called ``pong.kv`` in the same directory that will be automatically loaded
when the application is run. So create a new file called ``*pong.kv*`` and add
the following contents.
.. include:: ../../../examples/tutorials/pong/steps/step2/pong.kv
:literal:
.. literalinclude:: ../../../examples/tutorials/pong/steps/step2/pong.kv
:language: kv
:linenos:
If you run the app now, you should see a vertical bar in the middle, and two
zeros where the player scores will be displayed.
@ -127,7 +128,9 @@ child widgets that will be automatically added, or a `canvas` section in
which you can add Graphics instructions that define how the widget itself is
rendered.
The first block inside the ``<PongGame>`` rule we have is a canvas block::
The first block inside the ``<PongGame>`` rule we have is a canvas block:
.. code-block:: kv
<PongGame>:
canvas:
@ -150,10 +153,12 @@ score once we have the logic for that implemented. But the labels already
look good, since we set a bigger font_size, and positioned them relatively
to the root widget. The ``root`` keyword can be used inside child block to
refer back to the parent/root widget the rule applies to (``PongGame`` in this
case)::
case):
.. code-block:: kv
<PongGame>:
...
# ...
Label:
font_size: 70
@ -207,7 +212,9 @@ Here is the python code for the PongBall class::
self.pos = Vector(*self.velocity) + self.pos
And here is the kv rule used to draw the ball as a white circle::
And here is the kv rule used to draw the ball as a white circle:
.. code-block:: kv
<PongBall>:
size: 50, 50
@ -232,8 +239,9 @@ Here is the entire updated python code and kv file for this step:
:literal:
pong.kv:
.. include:: ../../../examples/tutorials/pong/steps/step3/pong.kv
:literal:
.. literalinclude:: ../../../examples/tutorials/pong/steps/step3/pong.kv
:language: kv
:linenos:
Adding ball animation
@ -308,7 +316,9 @@ inside the ``update`` method and even make it bounce of the edges::
self.ball.velocity_x *= -1
Don't forget to hook it up in the kv file, by giving the child widget an id
and setting the games property to that id::
and setting the games property to that id:
.. code-block:: kv
<PongGame>:
ball: pong_ball
@ -337,8 +347,9 @@ Here is the entire code for this step:
:literal:
pong.kv:
.. include:: ../../../examples/tutorials/pong/steps/step4/pong.kv
:literal:
.. literalinclude:: ../../../examples/tutorials/pong/steps/step4/pong.kv
:language: kv
:linenos:
Connect input event
-------------------
@ -401,8 +412,9 @@ And here it is in context. Pretty much done:
pong.kv:
.. include:: ../../../examples/tutorials/pong/steps/step5/pong.kv
:literal:
.. literalinclude:: ../../../examples/tutorials/pong/steps/step5/pong.kv
:language: kv
:linenos:
Where to go now?

View File

@ -299,8 +299,8 @@ class App(EventDispatcher):
#: configuration. Can be used to query some config token in the build()
self.config = None
#: Root widget set by the :func:`build` method or by the
#: :func:`load_kv` method if the kv file contains a root widget.
#: Root widget set by the :meth:`build` method or by the
#: :meth:`load_kv` method if the kv file contains a root widget.
self.root = None
def build(self):
@ -440,9 +440,9 @@ class App(EventDispatcher):
'''
if platform == 'android':
defaultpath = '/sdcard/.%(appname).ini'
defaultpath = '/sdcard/.%(appname)s.ini'
elif platform == 'ios':
defaultpath = '~/Documents/%(appname).ini'
defaultpath = '~/Documents/%(appname)s.ini'
elif platform == 'win':
defaultpath = defaultpath.replace('/', sep)
return expanduser(defaultpath) % {

View File

@ -316,6 +316,10 @@ class ImageLoader(object):
# extract extensions
ext = filename.split('.')[-1].lower()
# prevent url querystrings
if filename.startswith((('http://', 'https://'))):
ext = ext.split('?')[0]
# special case. When we are trying to load a "zip" file with image, we
# will use the special zip_loader in ImageLoader. This might return a
# sequence of images contained in the zip.
@ -565,7 +569,10 @@ class Image(EventDispatcher):
if image:
# we found an image, yeah ! but reset the texture now.
self.image = image
if not image.keep_data and self._keep_data:
# if image.__class__ is core image then it's a texture
# from atlas or other sources and has no data so skip
if (image.__class__ != self.__class__ and
not image.keep_data and self._keep_data):
self.remove_from_cache()
self._filename = ''
self._set_filename(value)

View File

@ -287,6 +287,8 @@ class LabelBase(object):
# calculate the word width
ww, wh = 0, 0
if word == '':
ww, wh = get_extents(' ')
for glyph in word:
gw, gh = cache[glyph]
ww += gw

View File

@ -198,6 +198,7 @@ class MarkupLabel(MarkupLabelBase):
# verify that each glyph have size
glyphs = list(set(word))
glyphs.append(' ')
get_extents = self.get_extents
for glyph in glyphs:
if not glyph in cache:
@ -219,7 +220,7 @@ class MarkupLabel(MarkupLabelBase):
for part in re.split(r'( |\n)', word):
if part == '':
continue
part = ' '
if part == '\n':
# put a new line!
@ -266,7 +267,7 @@ class MarkupLabel(MarkupLabelBase):
y = 0
w, h = self._size
refs = self._refs
no_of_lines = len(self._lines)
txt_height = sum(line[1] for line in self._lines)
for line in self._lines:
lh = line[1]
@ -283,9 +284,9 @@ class MarkupLabel(MarkupLabelBase):
# vertical alignement
if y == 0:
if av == 1:
y = int((h - (lh*no_of_lines))/2)
y = int((h - txt_height)/2)
elif av == 2:
y = h - (lh*(no_of_lines))
y = h - (txt_height)
for pw, ph, part, options in line[2]:

View File

@ -206,10 +206,7 @@ class MouseMotionEventProvider(MotionEventProvider):
self.remove_touch(cur)
self.current_drag = None
width, height = EventLoop.window.system_size
rx = x / float(width)
ry = 1. - y / float(height)
cur = self.find_touch(rx, ry)
cur = self.current_drag
if (button in ('left', 'scrollup', 'scrolldown') or
self.disable_multitouch) and cur and not ('ctrl' in modifiers):
self.remove_touch(cur)

View File

@ -105,7 +105,7 @@ from functools import partial
class RecorderMotionEvent(MotionEvent):
def depack(self, args):
for key, value in args.iteritems():
for key, value in args.items():
setattr(self, key, value)
super(RecorderMotionEvent, self).depack(args)
@ -183,10 +183,10 @@ class Recorder(EventDispatcher):
def on_motion(self, window, etype, motionevent):
if not self.record:
return
args = {}
for arg in self.record_attrs:
if hasattr(motionevent, arg):
args[arg] = getattr(motionevent, arg)
args = dict((arg, getattr(motionevent, arg))
for arg in self.record_attrs if hasattr(motionevent, arg))
args['profile'] = [x for x in motionevent.profile if x in
self.record_profile_mask]
self.record_fd.write('%r\n' % (
@ -200,7 +200,7 @@ class Recorder(EventDispatcher):
(time() - self.record_time, etype, 0, {
'key': key,
'scancode': kwargs.get('scancode'),
'codepoint': kwargs.get('codepoint') or kwargs.get('unicode'),
'codepoint': kwargs.get('codepoint', kwargs.get('unicode')),
'modifier': kwargs.get('modifier'),
'is_touch': False}), ))
self.counter += 1
@ -263,12 +263,12 @@ class Recorder(EventDispatcher):
EventLoop.add_input_provider(self)
def update(self, dispatch_fn):
if len(self.play_data) == 0:
if not self.play_data:
Logger.info('Recorder: Playing finished.')
self.play = False
dt = time() - self.play_time
while len(self.play_data):
while self.play_data:
event = self.play_data[0]
assert(len(event) == 4)
if event[0] > dt:
@ -290,21 +290,21 @@ class Recorder(EventDispatcher):
'on_key_down',
args['key'],
args['scancode'],
args['codepoint'] or args['unicode'],
args['codepoint'],
args['modifier'])
elif etype == 'keyup':
self.window.dispatch(
'on_key_up',
args['key'],
args['scancode'],
args['codepoint'] or args['unicode'],
args['codepoint'],
args['modifier'])
elif etype == 'keyboard':
self.window.dispatch(
'on_keyboard',
args['key'],
args['scancode'],
args['codepoint'] or args['unicode'],
args['codepoint'],
args['modifier'])
if me:

View File

View File

View File

@ -127,6 +127,20 @@ class FileChooserController(FloatLayout):
'''Base for implementing a FileChooser. Don't use that class directly,
preferring to use an implementation like :class:`FileChooserListView` or
:class:`FileChooserIconView`.
:Events:
`on_entry_added`: entry, parent
Fired when a root-level entry is added to the file list.
`on_entries_cleared`
Fired when the the entries list is cleared. Usally when the
root is refreshed.
`on_subentry_to_entry`: entry, parent
Fired when a sub-entry is added to an existing entry.
`on_remove_subentry`: entry, parent
Fired when entries are removed from an entry. Usually when
a node is closed.
`on_submit`: selection, touch
Fired when a file has been selected with a double-tap.
'''
_ENTRY_TEMPLATE = None

View File

@ -56,7 +56,7 @@ class Image(Widget):
source = StringProperty(None)
'''Filename / source of your image.
:data:`source` a :class:`~kivy.properties.StringProperty`, default to None.
:data:`source` is a :class:`~kivy.properties.StringProperty`, default to None.
'''
texture = ObjectProperty(None, allownone=True)

View File

@ -169,7 +169,7 @@ class Label(Widget):
def texture_update(self, *largs):
'''Force texture recreation with the current Label properties.
After this function call, the :data:`texture` and :data`texture_size`
After this function call, the :data:`texture` and :data:`texture_size`
will be updated in this order.
'''
self.texture = None
@ -365,7 +365,7 @@ class Label(Widget):
The :data:`texture` update is scheduled for the next frame. If you need
the texture immediately after changing a property, you have to call
the :func:`texture_update` function before accessing :data:`texture`::
the :meth:`texture_update` method before accessing :data:`texture`::
l = Label(text='Hello world')
# l.texture is good
@ -383,9 +383,9 @@ class Label(Widget):
.. warning::
The data:`texture_size` is set after the :data:`texture` property. If
The :data:`texture_size` is set after the :data:`texture` property. If
you listen for changes to :data:`texture`, :data:`texture_size` will not
be up-to-date in your callback. Bind to data:`texture_size` instead.
be up-to-date in your callback. Bind to :data:`texture_size` instead.
'''
mipmap = BooleanProperty(False)

View File

@ -64,7 +64,7 @@ class Layout(Widget):
def do_layout(self, *largs):
'''This function is called when a layout is needed, by a trigger.
If you are doing a new Layout subclass, don't call this function
directly, use :data:`_trigger_layout` instead.
directly, use :meth:`_trigger_layout` instead.
.. versionadded:: 1.0.8
'''
@ -72,13 +72,12 @@ class Layout(Widget):
def add_widget(self, widget, index=0):
widget.bind(
size = self._trigger_layout,
size_hint = self._trigger_layout)
size=self._trigger_layout,
size_hint=self._trigger_layout)
return super(Layout, self).add_widget(widget, index)
def remove_widget(self, widget):
widget.unbind(
size = self._trigger_layout,
size_hint = self._trigger_layout)
size=self._trigger_layout,
size_hint=self._trigger_layout)
return super(Layout, self).remove_widget(widget)

View File

@ -434,7 +434,7 @@ class RstDocument(ScrollView):
toctrees = DictProperty({})
'''Toctree of all loaded or preloaded documents. This dictionary is filled
when a rst document is explicitly loaded, or where :func:`preload` has been
when a rst document is explicitly loaded, or where :meth:`preload` has been
called.
If the document has no filename, e.g., when the document is loaded from a

View File

@ -21,8 +21,8 @@ constraints that you should consider:
For touch events, the scatter converts from the parent matrix to the scatter matrix
automatically in on_touch_down/move/up events. If you are doing things
manually, you will need to use :func:`~kivy.uix.widget.Widget.to_parent`,
:func:`~kivy.uix.widget.Widget.to_local`.
manually, you will need to use :meth:`~kivy.uix.widget.Widget.to_parent`,
:meth:`~kivy.uix.widget.Widget.to_local`.
Usage
-----

View File

@ -115,9 +115,10 @@ __all__ = ('Screen', 'ScreenManager', 'ScreenManagerException',
'TransitionBase', 'ShaderTransition', 'SlideTransition', 'SwapTransition',
'FadeTransition', 'WipeTransition')
from kivy.logger import Logger
from kivy.event import EventDispatcher
from kivy.uix.floatlayout import FloatLayout
from kivy.properties import StringProperty, ObjectProperty, \
from kivy.properties import StringProperty, ObjectProperty, AliasProperty, \
NumericProperty, ListProperty, OptionProperty, BooleanProperty
from kivy.animation import Animation, AnimationTransition
from kivy.uix.relativelayout import RelativeLayout
@ -242,6 +243,8 @@ class TransitionBase(EventDispatcher):
'''(internal) Start the transition. This is automatically called by the
:class:`ScreenManager`.
'''
if self.is_active:
raise ScreenManagerException('start() is called twice!')
self.manager = manager
self._anim = Animation(d=self.duration, s=0)
self._anim.bind(on_progress=self._on_progress,
@ -560,21 +563,37 @@ class ScreenManager(FloatLayout):
default to None, read-only.
'''
def _get_screen_names(self):
return [s.name for s in self.screens]
screen_names = AliasProperty(_get_screen_names,
None, bind=('screens', ))
'''List of the names of all the :class:`Screen` widgets added. The list
is read only.
:data:`screens_names` is a :class:`~kivy.properties.AliasProperty`,
it is read-only and updated if the screen list changes, or the name
of a screen changes.
'''
def __init__(self, **kwargs):
super(ScreenManager, self).__init__(**kwargs)
self.bind(pos=self._update_pos)
def _screen_name_changed(self, screen, name):
self.property('screen_names').dispatch(self)
if screen == self.current_screen:
self.current = name
def add_widget(self, screen):
if not isinstance(screen, Screen):
raise ScreenManagerException(
'ScreenManager accept only Screen widget.')
if screen.name in [s.name for s in self.screens]:
raise ScreenManagerException(
'Name %r already used' % screen.name)
if screen.manager:
raise ScreenManagerException(
'Screen already managed by another ScreenManager.')
screen.manager = self
screen.bind(name=self._screen_name_changed)
self.screens.append(screen)
if self.current is None:
self.current = screen.name
@ -592,6 +611,8 @@ class ScreenManager(FloatLayout):
screen = self.get_screen(value)
if not screen:
return
if screen == self.current_screen:
return
previous_screen = self.current_screen
self.current_screen = screen
@ -608,9 +629,13 @@ class ScreenManager(FloatLayout):
'''Return the screen widget associated to the name, or None if not
found.
'''
for screen in self.screens:
if screen.name == name:
return screen
matches = [s for s in self.screens if s.name == name]
num_matches = len(matches)
if num_matches == 0:
raise ScreenManagerException('No Screen with name "%s".' % name)
if num_matches > 1:
Logger.warn('Multiple screens named "%s": %s' % (name, matches))
return matches[0]
def next(self):
'''Return the name of the next screen from the screen list.

View File

@ -84,7 +84,7 @@ pairs to the properties of that class, i.e., "title": "Windows" sets the
:data:`SettingTitle.title` property to "Windows".
To load the JSON example to a :class:`Settings` instance, use the
:data:`Settings.add_json_panel` method. It will automatically instantiate
:meth:`Settings.add_json_panel` method. It will automatically instantiate
:class:`SettingsPanel` and add it to :class:`Settings`::
from kivy.config import ConfigParser

View File

@ -97,8 +97,8 @@ class Spinner(Button):
is_open = BooleanProperty(False)
'''By default, the spinner is not open. Set to true to open it.
:data: `is_open` is a :class: `~kivy.properties.BooleanProperty`,
default to False.
:data:`is_open` is a :class:`~kivy.properties.BooleanProperty`, default to
False.
.. versionadded:: 1.4.0
'''

View File

@ -543,7 +543,7 @@ class TreeView(Widget):
selected_node = AliasProperty(get_selected_node, None,
bind=('_selected_node', ))
'''Node selected by :func:`TreeView.select_node`, or by touch.
'''Node selected by :meth:`TreeView.select_node`, or by touch.
:data:`selected_node` is a :class:`~kivy.properties.AliasProperty`, defaults
to None, and is read-only.

View File

@ -128,6 +128,12 @@ class VKeyboard(Scatter):
VKeyboard is an onscreen keyboard with multitouch support.
Its layout is entirely customizable and you can switch between available
layouts using a button in the bottom right of the widget.
:Events:
`on_key_down`: keycode, internal, modifiers
Fired when the keyboard received a key down event (key press).
`on_key_up`: keycode, internal, modifiers
Fired when the keyboard received a key up event (key release).
'''
target = ObjectProperty(None, allownone=True)
@ -434,7 +440,6 @@ class VKeyboard(Scatter):
# the goal now is to map both point, calculate the diff between them
diff = dpos - cpos
# we still have an issue, self.pos represent the bounding box, not the
# 0,0 coordinate of the scatter. we need to apply also the diff between
# them (inside and outside coordinate matrix). It's hard to explain, but
@ -582,7 +587,7 @@ class VKeyboard(Scatter):
key_nb = 0
for pos, size in layout_geometry['LINE_%d' % line_nb]:
# retrieve the relative text
text = layout[layout_mode +'_'+ str(line_nb)][key_nb][0]
text = layout[layout_mode + '_' + str(line_nb)][key_nb][0]
l = Label(text=text, font_size=font_size, pos=pos, size=size,
font_name=self.font_name)
self.add_widget(l)
@ -604,8 +609,8 @@ class VKeyboard(Scatter):
mtop, mright, mbottom, mleft = self.margin_hint
# get the line of the layout
e_height = h - (mbottom + mtop) * h # efficient height in pixels
line_height = e_height / layout_rows # line height in px
e_height = h - (mbottom + mtop) * h # efficient height in pixels
line_height = e_height / layout_rows # line height in px
y = y - mbottom * h
line_nb = layout_rows - int(y / line_height)
@ -616,13 +621,13 @@ class VKeyboard(Scatter):
# get the key within the line
key_index = ''
current_key_index =0
current_key_index = 0
for key in layout_geometry['LINE_HINT_%d' % line_nb]:
if x_hint >= key[0][0] and x_hint < key[0][0] + key[1][0]:
key_index = current_key_index
break
else:
current_key_index +=1
current_key_index += 1
if key_index == '':
return None

View File

@ -25,13 +25,13 @@ Our widget class is designed with a couple of principles in mind:
Often you want to know if a certain point is within the bounds of your
widget. An example would be a button widget where you want to only
trigger an action when the button itself is actually touched.
For this, you can use the :func:`Widget.collide_point` method, which
For this, you can use the :meth:`Widget.collide_point` method, which
will return True if the point you pass it is inside the axis-aligned
bounding box defined by the widget's position and size.
If a simple AABB is not sufficient, you can override the method to
perform the collision checks with more complex shapes, e.g., a polygon.
You can also check if a widget collides with another widget with
:func:`Widget.collide_widget`.
:meth:`Widget.collide_widget`.
Using Properties
----------------
@ -187,7 +187,7 @@ class Widget(EventDispatcher):
def on_touch_move(self, touch):
'''Receive a touch move event.
See :func:`on_touch_down` for more information
See :meth:`on_touch_down` for more information
'''
for child in self.children[:]:
if child.dispatch('on_touch_move', touch):
@ -196,7 +196,7 @@ class Widget(EventDispatcher):
def on_touch_up(self, touch):
'''Receive a touch up event.
See :func:`on_touch_down` for more information
See :meth:`on_touch_down` for more information
'''
for child in self.children[:]:
if child.dispatch('on_touch_up', touch):
@ -468,7 +468,7 @@ class Widget(EventDispatcher):
:data:`children` is a :class:`~kivy.properties.ListProperty` instance,
default to an empty list.
Use :func:`add_widget` and :func:`remove_widget` for manipulating the
Use :meth:`add_widget` and :meth:`remove_widget` for manipulating the
children list. Don't manipulate the children list directly until you know
what you are doing.
'''

View File

@ -325,6 +325,9 @@ setup(
'kivy.tools',
'kivy.tools.packaging',
'kivy.tools.packaging.pyinstaller_hooks',
'kivy.tools.highlight',
'kivy.tools.highlight.pygments',
'kivy.tools.extensions',
'kivy.uix', ],
package_dir={'kivy': 'kivy'},
package_data={'kivy': [
@ -340,10 +343,14 @@ setup(
'data/glsl/*.png',
'data/glsl/*.vs',
'data/glsl/*.fs',
'tools/highlight/*.vim',
'tools/highlight/*.el',
'tools/packaging/README.txt',
'tools/packaging/win32/kivy.bat',
'tools/packaging/win32/kivyenv.sh',
'tools/packaging/win32/README.txt',
'tools/packaging/osx/Info.plist',
'tools/packaging/osx/InfoPlist.strings',
'tools/packaging/osx/kivy.sh']},
data_files=examples.items(),
classifiers=[