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

This commit is contained in:
geojeff 2012-10-23 12:05:04 -05:00
commit 29ff3259e9
42 changed files with 899 additions and 23 deletions

19
.travis.yml Normal file
View File

@ -0,0 +1,19 @@
language: python
python:
- "2.6"
- "2.7"
# command to install dependencies
before_install:
- sudo apt-get update
- sudo apt-get install python-dev libsdl-image1.2-dev libsdl-mixer1.2-dev libsdl-ttf2.0-dev libsdl1.2-dev libsmpeg-dev python-numpy libportmidi-dev ffmpeg libswscale-dev libavformat-dev libavcodec-dev libjpeg-dev libtiff4-dev libx11-6 libX11-dev
- sudo apt-get install python-setuptools python-opengl gstreamer0.10-plugins-good build-essential libgl1-mesa-dev libgles2-mesa-dev mercurial
- sudo apt-get install xvfb
install:
- pip install hg+http://bitbucket.org/pygame/pygame
- pip install --upgrade cython pil --use-mirrors
- make
# command to run tests
script:
- xvfb-run -s "+extension GLX" make test

View File

@ -16,7 +16,7 @@ it will be generated like this:
.. image:: images/api-button.jpg
It should be read like this: the "Button" class is into the "kivy.uix.button"
It should be read like this: the "Button" class is in the "kivy.uix.button"
module. So if you want to import that class in your code, write that::
from kivy.uix.button import Button

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

View File

@ -106,8 +106,8 @@ def callback_signature(app, what, name, obj, options, signature,
def setup(app):
import kivy
sys.path += [join(dirname(kivy.__file__), 'tools', 'highlight', 'pygments')]
from lexer_kivy import KivyLexer
sys.path += [join(dirname(kivy.__file__), 'extras')]
from highlight import KivyLexer
app.add_lexer('kv', KivyLexer())
app.add_autodocumenter(CythonMethodDocumenter)

Binary file not shown.

View File

@ -0,0 +1,18 @@
This is the Kivy Catalog viewer. It serves two purposes:
1. To showcase the various widgets available in Kivy
2. To allow interactive editing of Kivy language files
to get immediate feedback as to how they work
To use it, you'll need to install Kivy and it's dependencies
a la http://kivy.org/docs/installation/installation.html Then run
python main.py and browse or edit widgets to your heart's content.
Known bugs:
* The DropDown item I had tested completely crashes Kivy
* The GridLayout example could use some extra features
* If you try to start the app with focused set to true, weird stuff happens.
but it works fine if you set focused to true and press render.
* Video playback doesn't work for me, but this may be a dependency issue
* Popups are displayed inline
* Some widgets are still missing

View File

@ -0,0 +1,15 @@
#:kivy 1.4
AnchorLayout:
anchor_x: "right"
anchor_y: "bottom"
Button:
text: "Button 1"
size_hint: .2, .4
Button:
text: "Button 2"
size_hint: .4, .2
Button:
text: "Button 3"
size_hint: .2, .2

View File

@ -0,0 +1,14 @@
#:kivy 1.4
BoxLayout:
orientation: 'vertical'
padding: 20
spacing: 10
Button:
text: "Button 1"
size_hint: 1, None
Button:
text: "Button 2"
size_hint: 1, 0.5
Button:
text: "Button 3"

View File

@ -0,0 +1,27 @@
#:kivy 1.4
GridLayout:
cols: 2
Button:
text: "Button 1"
Button:
text: "Button 2"
font_size: 24
Button:
text: "Button 3"
background_color: .7, .7, 1, 1
Button:
text: "Button 4"
on_press: self.text = 'pressed'
on_release: self.text = 'Button 4'
ToggleButton:
text: "A toggle button"
ToggleButton:
text: "a toggle button in a group"
group: "money"
ToggleButton:
text: "A toggle in the down state"
state: "down"
ToggleButton:
text: "another toggle button in a group"
group: "money"

View File

@ -0,0 +1,27 @@
#:kivy 1.4
GridLayout:
cols: 2
CheckBox:
Label:
text: "A checkbox"
active: True
CheckBox:
Label:
text: "Another checkbox"
CheckBox:
group: "money"
Label:
text: "A radio in a group"
CheckBox:
group: "money"
Label:
text: "Another radio in same group"
active: True
Switch:
Label:
text: "A Switch"
Switch:
active: True
Label:
text: "An active switch"

View File

@ -0,0 +1,19 @@
#:kivy 1.4
BoxLayout:
# Double as a Tabbed Panel Demo!
TabbedPanel:
tab_pos: "top_right"
default_tab_text: "List View"
default_tab_content: list_view_tab
TabbedPanelHeader:
text: 'Icon View'
content: icon_view_tab
FileChooserListView:
id: list_view_tab
FileChooserIconView:
id: icon_view_tab
show_hidden: True

View File

@ -0,0 +1,16 @@
#:kivy 1.4
FloatLayout:
Button:
text: "Button 1"
pos: 100, 100
size_hint: .2, .4
Button:
text: "Button 2"
pos: 200, 200
size_hint: .4, .2
Button:
text: "Button 3"
pos_hint: {'x': .8, 'y': .6}
size_hint: .2, .2

View File

@ -0,0 +1,20 @@
#:kivy 1.4
GridLayout:
cols: 2
Button:
text: "Button 1"
size_hint_x: None
width: 100
Button:
text: "Button 2"
Button:
text: "Button 3"
size_hint_x: None
Button:
text: "Button 4"
Button:
text: "Button 5"
Button:
text: "Button 6"
size_hint_x: None

View File

@ -0,0 +1,21 @@
#:kivy 1.4
GridLayout:
rows: 2
Label:
text: "Label 1"
Label:
text: "Label with\nmultiple lines"
Label:
text: "Label [color=ff3333]with[/color] [color=3333ff][b]markup[/b][/color]"
markup: True
Label:
text: "Label with [ref=reference]reference[/ref]"
markup: True
on_ref_press: self.text = "ref clicked"
Label:
text: "different font"
bold: True
font_name: "DroidSansMono.ttf"
font_size: 32
valign: "bottom"

View File

@ -0,0 +1,9 @@
#:kivy 1.4
BoxLayout:
orientation: "vertical"
Image:
source: "../../widgets/softboy.png"
Video:
source: "../../widgets/softboy.avi"
state: "play"

View File

@ -0,0 +1,6 @@
#:kivy 1.4
Label:
text_size: self.width-60, self.height-60
valign: "middle"
text: "The Kivy Catalog is an interactive showcase of Kivy Widgets defined in the Kivy language. For each widget you see, you can directly edit the .kv language syntax to see what effects your changes have on the widget. Click 'Render' or hit 'Ctrl-S' to view your changes.\n\nThere is also a playground on this tab where you can test your Kivy language code directly. This is beta software. The basics seem to work, but some widgets are missing or don't have the ideal .kv representation. Not all widgets are represented yet. It is trivial to add a new .kv file to the interface.\n\nPull requests are welcome."

View File

@ -0,0 +1,23 @@
#:kivy 1.4
BoxLayout:
orientation: "vertical"
Bubble:
size_hint: (None, None)
size: (150, 50)
pos_hint: {'center_x': .5, 'y': .6}
arrow_pos: 'bottom_mid'
orientation: 'horizontal'
BubbleButton:
text: 'Click'
BubbleButton:
text: 'A'
BubbleButton:
text: 'Bubble'
Popup:
id: popup
title: "An example popup"
content: popupcontent
Label:
id: popupcontent
text: "Some text\nin the popup"

View File

@ -0,0 +1,17 @@
#:kivy 1.4
BoxLayout:
orientation: 'vertical'
padding: 50
ProgressBar:
id: bar
value: 140
max: 300
Slider:
id: slider
max: 200
value: 140
on_value: bar.value = self.value
Slider:
orientation: 'vertical'
on_value: slider.value = self.value

View File

@ -0,0 +1,5 @@
#:kivy 1.4
BoxLayout:
RstDocument:
text: ".. _top:\n\nHello world\n===========\n\nThis is an **emphased text**, some ``interpreted text``.\nAnd this is a reference to top_::\n\n $ print 'Hello world'\n"

View File

@ -0,0 +1,16 @@
#:kivy 1.4
FloatLayout:
Scatter:
size_hint: None, None
size: 100, 100
pos: 100, 100
Image:
source: "../../widgets/softboy.png"
Scatter:
size_hint: None, None
size: 100, 100
pos: 100, 100
do_rotation: False
Label:
text: "something"

View File

@ -0,0 +1,10 @@
#:kivy 1.4
BoxLayout:
orientation: 'vertical'
Spinner:
text: "Work"
values: "Work", "Home", "Mobile", "Skype"
size_hint: (None, None)
size: (100, 44)
# Wanted to put DropDown here, too, but it seems not to be working too well when loaded from .kv

View File

@ -0,0 +1,25 @@
#:kivy 1.4
StackLayout:
orientation: 'tb-lr'
padding: 10
spacing: 5
Button:
text: "Button 1"
size_hint: .2, .4
width: 100
Button:
text: "Button 2"
size_hint: .2, .4
Button:
text: "Button 3"
size_hint: .2, .4
Button:
text: "Button 4"
size_hint: .2, .4
Button:
text: "Button 5"
size_hint: .2, .4
Button:
text: "Button 6"
size_hint: .2, .4

View File

@ -0,0 +1,20 @@
#:kivy 1.4
BoxLayout:
orientation: "vertical"
TextInput:
text: "Single Line Input"
multiline: False
TextInput:
text: "Text Input, start typing here\nmultiline\nsupport"
background_color: .8, .8, 0, 1
size_hint: 1, 3
TextInput:
text: "Password (but you can't see it)"
password: True
multiline: False
on_text: viewer.text = self.text
TextInput:
id: viewer
read_only: True
text: "edit the password to see it here"

View File

@ -0,0 +1,120 @@
#:kivy 1.4
[ContainerToggle@ToggleButton]:
group: "container_toggle"
text: ctx.text
on_press: root.parent.parent.parent.show_kv(*args)
state: ctx.state if hasattr(ctx, "state") else "normal"
<Catalog>:
language_box: language_box
screen_manager: screen_manager
BoxLayout:
BoxLayout:
size_hint: None, 1
orientation: "vertical"
ContainerToggle:
text: "Welcome"
state: "down"
ContainerToggle:
text: "Float Layout"
ContainerToggle:
text: "Box Layout"
ContainerToggle:
text: "Anchor Layout"
ContainerToggle:
text: "Grid Layout"
ContainerToggle:
text: "Stack Layout"
ContainerToggle:
text: "Buttons"
ContainerToggle:
text: "Labels"
ContainerToggle:
text: "Booleans"
ContainerToggle:
text: "Progress Bar"
ContainerToggle:
text: "Media"
ContainerToggle:
text: "Text"
ContainerToggle:
text: "Popups"
ContainerToggle:
text: "Selectors"
ContainerToggle:
text: "File Choosers"
ContainerToggle:
text: "Scatter"
ContainerToggle:
text: "ReST"
ScreenManager:
id: screen_manager
Screen:
name: "Welcome"
PlaygroundContainer:
Screen:
name: "Float Layout"
FloatLayoutContainer
Screen:
name: "Box Layout"
BoxLayoutContainer:
Screen:
name: "Anchor Layout"
AnchorLayoutContainer:
Screen:
name: "Grid Layout"
GridLayoutContainer:
Screen:
name: "Stack Layout"
StackLayoutContainer:
Screen:
name: "Buttons"
ButtonContainer:
Screen:
name: "Labels"
LabelContainer:
Screen:
name: "Booleans"
CheckBoxContainer:
Screen:
name: "Progress Bar"
ProgressBarContainer:
Screen:
name: "Media"
MediaContainer:
Screen:
name: "Text"
TextContainer:
Screen:
name: "Popups"
PopupContainer:
Screen:
name: "Selectors"
SelectorsContainer:
Screen:
name: "File Choosers"
FileChooserContainer:
Screen:
name: "Scatter"
ScatterContainer:
Screen:
name: "ReST"
RestContainer:
BoxLayout:
id: bl
orientation: "vertical"
size_hint: None, 1
width: 400
KivyRenderTextInput:
text_size: self.width-20, self.height-20
font_name: "DroidSansMono.ttf"
valign: "top"
id: language_box
text: "This box will display the kivy language for whatever has been selected"
Button:
size_hint: 1, None
height: 50
text: "Render"
on_press: root.change_kv(*args)

View File

@ -0,0 +1,153 @@
import kivy
kivy.require('1.4.2')
import os
import sys
from kivy.app import App
from kivy.factory import Factory
from kivy.lang import Builder, Parser, ParserException
from kivy.properties import ObjectProperty
from kivy.config import Config
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.popup import Popup
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
print Config.get('graphics', 'width')
Config.set('graphics', 'width', '1024')
Config.set('graphics', 'height', '768')
'''List of classes that need to be instantiated in the factory from .kv files.
'''
CONTAINER_CLASSES = [c[:-3] for c in os.listdir('container_kvs')
if c.endswith('.kv')]
class Container(BoxLayout):
'''A container is essentially a class that loads its root from a known
.kv file.
The name of the .kv file is taken from the Container's class.
We can't just use kv rules because the class may be edited
in the interface and reloaded by the user.
See :meth: change_kv where this happens.
'''
def __init__(self, **kwargs):
super(Container, self).__init__(**kwargs)
parser = Parser(content=file(self.kv_file).read())
widget = Factory.get(parser.root.name)()
Builder._apply_rule(widget, parser.root, parser.root)
self.add_widget(widget)
@property
def kv_file(self):
'''Get the name of the kv file, a lowercase version of the class name.'''
return os.path.join('container_kvs',
self.__class__.__name__ + ".kv")
for class_name in CONTAINER_CLASSES:
globals()[class_name] = type(class_name, (Container,), {})
class KivyRenderTextInput(TextInput):
def _keyboard_on_key_down(self, window, keycode, text, modifiers):
is_osx = sys.platform == 'darwin'
# Keycodes on OSX:
ctrl, cmd = 64, 1024
key, key_str = keycode
if text and not key in (self.interesting_keys.keys() + [27]):
# This allows *either* ctrl *or* cmd, but not both.
if modifiers == ['ctrl'] or (is_osx and modifiers == ['meta']):
if key == ord('s'):
self.parent.parent.parent.change_kv(True)
return
super(KivyRenderTextInput, self)._keyboard_on_key_down(
window, keycode, text, modifiers)
class Catalog(BoxLayout):
'''Catalog of widgets. This is the root widget of the app. It contains
a tabbed pain of widgets that can be displayed and a textbox where .kv
language files for widgets being demoed can be edited.
The entire interface for the Catalog is defined in kivycatalog.kv, although
individual containers are defined in the container_kvs directory.
To add a container to the catalog,
first create the .kv file in container_kvs
The name of the file (sans .kv) will be the name of the widget available
inside the kivycatalog.kv
Finally modify kivycatalog.kv to add an AccordionItem
to hold the new widget.
Follow the examples in kivycatalog.kv to ensure the item
has an appropriate id and the class has been referenced.
You do not need to edit any python code, just .kv language files!
'''
language_box = ObjectProperty()
screen_manager = ObjectProperty()
def __init__(self, **kwargs):
super(Catalog, self).__init__(**kwargs)
self.show_kv(None)
def show_kv(self, object):
'''Called when an accordionitem is collapsed or expanded. If it
was expanded, we need to show the .kv language file associated with
the newly revealed container.'''
# if object is not passed, it's initialization, we just need to load
# the file
if object:
# one button must always be pressed, even if user presses it again
if object.state == "normal":
object.state = "down"
self.screen_manager.current = object.text
with open(self.screen_manager.current_screen.content.children[
0].kv_file) as file:
self.language_box.text = file.read()
def change_kv(self, button):
'''Called when the update button is clicked. Needs to update the
interface for the currently active kv widget, if there is one based
on the kv file the user entered. If there is an error in their kv
syntax, show a nice popup.'''
kv_container = self.screen_manager.current_screen.content.children[0]
try:
parser = Parser(content=self.language_box.text.encode('utf8'))
kv_container.clear_widgets()
widget = Factory.get(parser.root.name)()
Builder._apply_rule(widget, parser.root, parser.root)
kv_container.add_widget(widget)
except (SyntaxError, ParserException) as e:
content = Label(text=str(e), text_size=(350, None))
popup = Popup(title="Parse Error in Kivy Language Markup",
content=content, text_size=(350, None),
size_hint=(None, None), size=(400, 400))
popup.open()
except:
import traceback
traceback.print_exc()
popup = Popup(title="Boom",
content=Label(text="Something horrible happened while parsing your Kivy Language", text_size=(350, None)),
text_size=(350, None),
size_hint=(None, None), size=(400, 400))
popup.open()
class KivyCatalogApp(App):
'''The kivy App that runs the main root. All we do is build a catalog
widget into the root.'''
def build(self):
return Catalog()
if __name__ == "__main__":
KivyCatalogApp().run()

View File

@ -0,0 +1,82 @@
from kivy.app import App
from kivy.extras.highlight import KivyLexer
from kivy.factory import Factory
import pygments
example_text = '''
---------------------Python----------------------------------
import kivy
kivy.require('1.0.6') # replace with your current kivy version !
from kivy.app import App
from kivy.uix.button import Button
class MyApp(App):
def build(self):
return Button(text='Hello World')
if __name__ == '__main__':
MyApp().run()
----------------------Java------------------------------------
public static byte toUnsignedByte(int intVal) {
byte byteVal;
return (byte)(intVal & 0xFF);
}
---------------------kv lang-------------------------
#:kivy 1.0
<YourWidget>:
canvas:
Color:
rgb: .5, .5, .5
Rectangle:
pos: self.pos
size: self.size
-----------------HTML-----------------------------
<!-- Place this tag where you want the +1 button to render. -->
<div class="g-plusone" data-annotation="inline" data-width="300"></div>
<!-- Place this tag after the last +1 button tag. -->
<script type="text/javascript">
(function() {
var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
po.src = 'https://apis.google.com/js/plusone.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
})();
</script>
'''
class CodeInputTest(App):
def build(self):
b = Factory.BoxLayout(orientation='vertical')
languages = Factory.Spinner(
text='language',
values=sorted(['KvLexer', ] + pygments.lexers.LEXERS.keys()),
size_hint_y=None,
height='30pt')
languages.bind(text=self.change_lang)
b.add_widget(languages)
self.codeinput = Factory.CodeInput(
lexer=KivyLexer(),
font_name='data/fonts/DroidSansMono.ttf', font_size=12,
text=example_text)
b.add_widget(self.codeinput)
return b
def change_lang(self, instance, l):
if l == 'KvLexer':
lx = KivyLexer()
else:
lx = pygments.lexers.get_lexer_by_name(
pygments.lexers.LEXERS[l][2][0])
self.codeinput.lexer = lx
CodeInputTest().run()

View File

@ -192,7 +192,7 @@ class Atlas(EventDispatcher):
self.textures = textures
@staticmethod
def create(outname, filenames, size, padding=1):
def create(outname, filenames, size, padding=2):
'''This method can be used to create manually an atlas from a set of
images.
@ -204,11 +204,17 @@ class Atlas(EventDispatcher):
List of filename to put in the atlas
`size`: int
Size of an atlas image
`padding`: int, default to 1
Padding to put around each image. Care, if you put 0, they might
be some issues with OpenGL, because by default, Kivy texture are
using GL_CLAMP_TO_EDGE, and the edge is another image than
the image you'll want to display.
`padding`: int, default to 2
Padding to put around each image.
Be careful. If you're using a padding < 2, you might get issues
with border of the images. Because of the OpenGL linearization,
it might take the pixels of the adjacent image.
If you're using a padding >= 2, we'll automatically generate a
"border" of 1px of your image, around the image. If you look at
the result, don't be scared if the image inside it are not
exactly the same as yours :).
'''
# Thanks to
# omnisaurusgames.com/2011/06/texture-atlas-generation-using-python/
@ -232,7 +238,6 @@ class Atlas(EventDispatcher):
# the freebox tuple format is: outidx, x, y, w, h
freeboxes = [(0, 0, 0, size, size)]
numoutimages = 1
padding = 1
# full boxes are areas where we have placed images in the atlas
# the full box tuple format is: image, outidx, x, y, w, h, filename
@ -291,7 +296,16 @@ class Atlas(EventDispatcher):
outimages = [Image.new('RGBA', (size, size))
for i in range(0, int(numoutimages))]
for fb in fullboxes:
outimages[fb[1]].paste(fb[0], (fb[2], fb[3]))
x, y = fb[2], fb[3]
out = outimages[fb[1]]
out.paste(fb[0], (fb[2], fb[3]))
w, h = fb[0].size
if padding > 1:
out.paste(fb[0].crop((0, 0, w, 1)), (x, y - 1))
out.paste(fb[0].crop((0, h - 1, w, h)), (x, y + h))
out.paste(fb[0].crop((0, 0, 1, h)), (x - 1, y))
out.paste(fb[0].crop((w - 1, 0, w, h)), (x + w, y))
# save the output images
for idx, outimage in enumerate(outimages):

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 43 KiB

View File

@ -1 +1 @@
{"defaulttheme-0.png": {"player-play-overlay": [306, 396, 117, 115], "spinner_pressed": [91, 124, 29, 37], "progressbar_background": [220, 137, 24, 24], "media-playback-pause": [448, 344, 48, 48], "tab_btn_pressed": [465, 178, 32, 32], "image-missing": [399, 344, 48, 48], "filechooser_selected": [187, 393, 118, 118], "audio-volume-muted": [350, 344, 48, 48], "sliderv_background": [473, 404, 37, 41], "tab": [332, 228, 96, 32], "close": [490, 491, 20, 20], "ring": [1, 326, 185, 185], "vkeyboard_key_down": [121, 129, 32, 32], "vkeyboard_background": [187, 328, 64, 64], "checkbox_off": [300, 178, 32, 32], "bubble_arrow": [148, 162, 16, 10], "player-background": [228, 222, 103, 103], "bubble": [424, 446, 65, 65], "spinner": [61, 124, 29, 37], "sliderh_background": [148, 173, 41, 37], "audio-volume-medium": [301, 344, 48, 48], "media-playback-start": [1, 162, 48, 48], "tab_btn": [432, 178, 32, 32], "bubble_btn_pressed": [267, 178, 32, 32], "tree_closed": [490, 470, 20, 20], "switch-background": [429, 228, 83, 32], "filechooser_file": [332, 261, 64, 64], "checkbox_radio_off": [366, 178, 32, 32], "vkeyboard_key_normal": [154, 129, 32, 32], "checkbox_radio_on": [399, 178, 32, 32], "checkbox_on": [333, 178, 32, 32], "tree_opened": [490, 449, 20, 20], "button_pressed": [31, 124, 29, 37], "media-playback-stop": [50, 162, 48, 48], "audio-volume-high": [424, 397, 48, 48], "audio-volume-low": [252, 344, 48, 48], "bubble_btn": [234, 178, 32, 32], "modalview-background": [462, 271, 45, 54], "button": [1, 124, 29, 37], "progressbar": [187, 137, 32, 24], "switch-button": [190, 178, 43, 32], "filechooser_folder": [397, 261, 64, 64], "slider_cursor": [99, 162, 48, 48], "textinput_active": [1, 211, 114, 114], "textinput": [116, 214, 111, 111]}}
{"defaulttheme-0.png": {"player-play-overlay": [309, 395, 117, 115], "spinner_pressed": [384, 170, 29, 37], "progressbar_background": [483, 183, 24, 24], "media-playback-pause": [52, 159, 48, 48], "tab_btn_pressed": [138, 125, 32, 32], "image-missing": [2, 159, 48, 48], "filechooser_selected": [189, 392, 118, 118], "audio-volume-muted": [452, 342, 48, 48], "sliderv_background": [252, 166, 37, 41], "tab": [336, 225, 96, 32], "close": [240, 137, 20, 20], "ring": [2, 325, 185, 185], "vkeyboard_key_down": [172, 125, 32, 32], "vkeyboard_background": [189, 326, 64, 64], "checkbox_off": [449, 175, 32, 32], "bubble_arrow": [495, 500, 16, 10], "player-background": [231, 220, 103, 103], "bubble": [428, 445, 65, 65], "spinner": [353, 170, 29, 37], "sliderh_background": [468, 286, 41, 37], "audio-volume-medium": [402, 342, 48, 48], "media-playback-start": [102, 159, 48, 48], "tab_btn": [104, 125, 32, 32], "bubble_btn_pressed": [415, 175, 32, 32], "tree_closed": [262, 137, 20, 20], "switch-background": [428, 411, 83, 32], "filechooser_file": [336, 259, 64, 64], "checkbox_radio_off": [36, 125, 32, 32], "vkeyboard_key_normal": [206, 125, 32, 32], "checkbox_radio_on": [70, 125, 32, 32], "checkbox_on": [2, 125, 32, 32], "tree_opened": [284, 137, 20, 20], "button_pressed": [322, 170, 29, 37], "media-playback-stop": [152, 159, 48, 48], "audio-volume-high": [302, 342, 48, 48], "audio-volume-low": [352, 342, 48, 48], "bubble_btn": [479, 225, 32, 32], "modalview-background": [255, 336, 45, 54], "button": [291, 170, 29, 37], "progressbar": [468, 260, 32, 24], "switch-button": [434, 225, 43, 32], "filechooser_folder": [402, 259, 64, 64], "slider_cursor": [202, 159, 48, 48], "textinput_active": [2, 209, 114, 114], "textinput": [118, 212, 111, 111]}}

1
kivy/extras/__init__.py Normal file
View File

@ -0,0 +1 @@

View File

@ -1,3 +1,5 @@
'''Pygments lexer for kv language
'''
from pygments.lexer import RegexLexer, bygroups, using
from pygments.lexers.agile import PythonLexer
from pygments import highlight

View File

@ -81,6 +81,7 @@ r('Bubble', module='kivy.uix.bubble')
r('BubbleButton', module='kivy.uix.bubble')
r('Camera', module='kivy.uix.camera')
r('Carousel', module='kivy.uix.carousel')
r('CodeInput', module='kivy.uix.codeinput')
r('CheckBox', module='kivy.uix.checkbox')
r('DropDown', module='kivy.uix.dropdown')
r('FloatLayout', module='kivy.uix.floatlayout')

View File

@ -7,10 +7,10 @@ Input Postprocessing
__all__ = ('kivy_postproc_modules', )
import os
from doubletap import InputPostprocDoubleTap
from ignorelist import InputPostprocIgnoreList
from retaintouch import InputPostprocRetainTouch
from dejitter import InputPostprocDejitter
from kivy.input.postproc.doubletap import InputPostprocDoubleTap
from kivy.input.postproc.ignorelist import InputPostprocIgnoreList
from kivy.input.postproc.retaintouch import InputPostprocRetainTouch
from kivy.input.postproc.dejitter import InputPostprocDejitter
# Mapping of ID to module
kivy_postproc_modules = {}

View File

@ -43,7 +43,7 @@ can be quickly listed by using the '.' operator and pressing 'tab.' Try this
code in an Ipython shell.::
from kivy.interactive import InteractiveLauncher
from kivy.app imort App
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import Color, Ellipse

View File

@ -1,4 +1,4 @@
from common import GraphicUnitTest
from kivy.tests.common import GraphicUnitTest
class FileChooserTestCase(GraphicUnitTest):

View File

@ -5,7 +5,7 @@ Graphics tests
Testing the simple vertex instructions
'''
from common import GraphicUnitTest
from kivy.tests.common import GraphicUnitTest
class VertexInstructionTestCase(GraphicUnitTest):

View File

@ -1,4 +1,4 @@
from common import GraphicUnitTest
from kivy.tests.common import GraphicUnitTest
class Issue609(GraphicUnitTest):

View File

@ -3,7 +3,7 @@ Anchor layout unit test
=======================
'''
from common import GraphicUnitTest
from kivy.tests.common import GraphicUnitTest
class UIXAnchorLayoutTestcase(GraphicUnitTest):

View File

@ -6,7 +6,7 @@ Order matter.
On the screen, most of example must have the red->blue->green order.
'''
from common import GraphicUnitTest
from kivy.tests.common import GraphicUnitTest
class UIXBoxLayoutTestcase(GraphicUnitTest):

View File

@ -1,4 +1,4 @@
from common import GraphicUnitTest
from kivy.tests.common import GraphicUnitTest
class UIXWidgetTestCase(GraphicUnitTest):

176
kivy/uix/codeinput.py Normal file
View File

@ -0,0 +1,176 @@
# -*- coding: utf-8 -*-
'''
Code Input
==========
.. versionadded:: 1.5.0
.. image:: images/codeinput.jpg
The :class:`CodeInput` provides a box of editable highlited text, like the ones
shown in the image.
It supports all the features supported by the :class:`~kivy.uix.textinput` and
Code highliting for `languages supported by pygments
<http://pygments.org/docs/lexers/>`_ along with `KivyLexer` for `KV Language`
highliting.
Usage example
-------------
To create a CodeInput with highliting for `KV language`::
from kivy.uix.codeinput import CodeInput
from kivy.extras.highlight import KivyLexer
codeinput = CodeInput(lexer=KivyLexer())
To create a CodeInput with highliting for `Cython`::
from kivy.uix.codeinput import CodeInput
from pygments.lexers import CythonLexer
codeinput = CodeInput(lexer=CythonLexer())
'''
__all__ = ('CodeInput', )
from pygments import highlight
from pygments import lexers
from pygments.formatters import BBCodeFormatter
from kivy.uix.textinput import TextInput
from kivy.core.text.markup import MarkupLabel as Label
from kivy.cache import Cache
from kivy.properties import ObjectProperty
Cache_get = Cache.get
Cache_append = Cache.append
# TODO: fix empty line rendering
# TODO: color chooser for keywords/strings/...
class CodeInput(TextInput):
'''CodeInput class, used for displaying highlited code.
'''
lexer = ObjectProperty(None)
'''This holds the selected Lexer used by pygments to highlite the code
:data:`lexer` is a :class:`~kivy.properties.ObjectProperty` defaults to
`PythonLexer`
'''
def __init__(self, **kwargs):
self.formatter = BBCodeFormatter()
self.lexer = lexers.PythonLexer()
self.text_color = (0, 0, 0, 1)
self._label_cached = Label()
super(CodeInput, self).__init__(**kwargs)
self._line_options = kw = self._get_line_options()
self._label_cached = Label(**kw)
#use text_color as foreground color
text_color = kwargs.get('foreground_color')
if text_color:
self.text_color = (text_color[0], text_color[1], text_color[2],
text_color[3])
# set foreground to white to allow text colors to show
# use text_color as the default color in bbcodes
self.foreground_color = [1, 1, 1, 1]
if not kwargs.get('background_color'):
self.background_color = [.9, .92, .92, 1]
def _create_line_label(self, text):
# Create a label from a text, using line options
ntext = text.replace('\n', '').replace('\t', ' ' * self.tab_width)
if self.password:
ntext = '*' * len(ntext)
ntext = self._get_bbcode(ntext)
kw = self._get_line_options()
cid = '%s\0%s' % (ntext, str(kw))
texture = Cache_get('textinput.label', cid)
if not texture:
# FIXME right now, we can't render very long line...
# if we move on "VBO" version as fallback, we won't need to do this.
# try to found the maximum text we can handle
label = Label(text=ntext, **kw)
if text.find('\n') > 0:
label.text = ''
else:
label.text = ntext
try:
label.refresh()
except ValueError:
pass
# ok, we found it.
texture = label.texture
Cache_append('textinput.label', cid, texture)
label.text = ''
return texture
def _get_line_options(self):
kw = super(CodeInput, self)._get_line_options()
kw['markup'] = True
kw['valign'] = 'top'
return kw
def _get_bbcode(self, ntext):
# get bbcoded text for python
try:
ntext[0]
# replace brackets with special chars that aren't highlighted
# by pygment. can't use &bl; ... cause & is highlighted
# if at some time support for braille is added then replace these
# characters with something else
ntext = ntext.replace('[', u'⣿;').replace(']', u'⣾;')
ntext = highlight(ntext, self.lexer, self.formatter)
ntext = ntext.replace(u'⣿;', '&bl;').replace(u'⣾;', '&br;')
# replace special chars with &bl; and &br;
ntext = ''.join(('[color=rgba', str(self.text_color), ']',
ntext, '[/color]'))
ntext = ntext.replace('\n', '')
return ntext
except IndexError:
return ''
# overriden to prevent cursor position off screen
def _cursor_offset(self):
'''Get the cursor x offset on the current line
'''
offset = 0
try:
if self.cursor_col:
offset = self._get_text_width(
self._lines[self.cursor_row][:self.cursor_col])
except:
pass
finally:
return offset
def on_lexer(self, instance, value):
self._trigger_refresh_text()
if __name__ == '__main__':
from kivy.extras.highlight import KivyLexer
from kivy.app import App
class CodeInputTest(App):
def build(self):
return CodeInput(lexer=KivyLexer(),
font_name='data/fonts/DroidSansMono.ttf', font_size=12,
text='''
#:kivy 1.0
<YourWidget>:
canvas:
Color:
rgb: .5, .5, .5
Rectangle:
pos: self.pos
size: self.size''')
CodeInputTest().run()