Add a new showcase example that allows interactive editing of Kivy language code to see how it affects the widgets.

This commit is contained in:
Dusty Phillips 2012-10-16 11:44:34 -06:00
parent 305bf9e839
commit cdb11c4aa9
21 changed files with 607 additions and 0 deletions

Binary file not shown.

View File

@ -0,0 +1,20 @@
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:
* StackLayout is misbehaving
* The DropDown item I had tested completely crashes Kivy
* Scatter seems to do some weird translation on multitouch. This is probably an Accordion related bug
* 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,4 @@
#:kivy 1.4
Label:
text: "Paste your Kivy code in here and render!"

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
BoxLayout:
Scatter:
size_hint: None, None
size: 100, 100
pos: 100, 100
Image:
source: '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, .5
width: 100
Button:
text: "Button 2"
size_hint: .2, .5
Button:
text: "Button 3"
size_hint: .2, .5
Button:
text: "Button 4"
size_hint: .2, .5
Button:
text: "Button 5"
size_hint: .2, .5
Button:
text: "Button 6"
size_hint: .2, .5

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,161 @@
#:kivy 1.4
<Catalog>:
language_box: language_box
BoxLayout:
spacing: 5
TabbedPanel:
size_hint: .6, 1
tab_pos: "left_top"
default_tab_text: "Introduction"
default_tab_content: introduction_tab
on_default_tab: root.show_kv(*args)
Accordion:
id: introduction_tab
AccordionItem:
on_collapse: root.show_kv(*args)
title: "Playground"
kv_container: playground
PlaygroundContainer:
id: playground
AccordionItem:
title: "Welcome"
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.\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."
TabbedPanelHeader:
text: 'Layouts'
content: layout_tab
on_state: root.show_kv(*args)
TabbedPanelHeader:
text: 'UX Widgets'
content: basic_widgets
on_state: root.show_kv(*args)
TabbedPanelHeader:
text: 'Complex'
content: complex_widgets
on_state: root.show_kv(*args)
Accordion:
id: layout_tab
AccordionItem:
on_collapse: root.show_kv(*args)
title: "FloatLayout"
kv_container: floatlayoutcontainer
FloatLayoutContainer:
id: floatlayoutcontainer
AccordionItem:
on_collapse: root.show_kv(*args)
title: "BoxLayout"
kv_container: boxlayoutcontainer
BoxLayoutContainer:
id: boxlayoutcontainer
AccordionItem:
on_collapse: root.show_kv(*args)
title: "AnchorLayout"
kv_container: anchorlayoutcontainer
AnchorLayoutContainer:
id: anchorlayoutcontainer
AccordionItem:
on_collapse: root.show_kv(*args)
title: "GridLayout"
kv_container: gridlayoutcontainer
GridLayoutContainer:
id: gridlayoutcontainer
AccordionItem:
on_collapse: root.show_kv(*args)
title: "StackLayout"
kv_container: stacklayoutcontainer
StackLayoutContainer:
id: stacklayoutcontainer
Accordion:
id: basic_widgets
AccordionItem:
on_collapse: root.show_kv(*args)
title: "Buttons"
kv_container: buttoncontainer
ButtonContainer:
id: buttoncontainer
AccordionItem:
on_collapse: root.show_kv(*args)
title: "Labels"
kv_container: labelcontainer
LabelContainer:
id: labelcontainer
AccordionItem:
on_collapse: root.show_kv(*args)
title: "Booleans"
kv_container: checkboxcontainer
CheckBoxContainer:
id: checkboxcontainer
AccordionItem:
on_collapse: root.show_kv(*args)
title: "Progress Bar"
kv_container: progressbarcontainer
ProgressBarContainer:
id: progressbarcontainer
AccordionItem:
on_collapse: root.show_kv(*args)
title: "Media"
kv_container: mediacontainer
MediaContainer:
id: mediacontainer
AccordionItem:
on_collapse: root.show_kv(*args)
title: "Text"
kv_container: textcontainer
TextContainer:
id: textcontainer
Accordion:
id: complex_widgets
AccordionItem:
on_collapse: root.show_kv(*args)
title: "Popups"
kv_container: popupcontainer
PopupContainer:
id: popupcontainer
AccordionItem:
on_collapse: root.show_kv(*args)
title: "Selectors"
kv_container: selectorscontainer
SelectorsContainer:
id: selectorscontainer
AccordionItem:
on_collapse: root.show_kv(*args)
title: "FileChoosers"
kv_container: filechoosercontainer
FileChooserContainer:
id: filechoosercontainer
AccordionItem:
on_collapse: root.show_kv(*args)
title: "Scatter"
kv_container: scatter
ScatterContainer:
id: scatter
AccordionItem:
on_collapse: root.show_kv(*args)
title: "ReST"
kv_container: rest
RestContainer:
id: rest
BoxLayout:
id: bl
orientation: "vertical"
size_hint: .4, 1
TextInput:
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,138 @@
import os
from kivy.app import App
from kivy.factory import Factory
from kivy.lang import Builder, Parser, ParserException
from kivy.properties import ObjectProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.popup import Popup
from kivy.uix.label import Label
'''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')]
def factoryable(class_name, parents, attrs):
'''Metaclass that automatically records the resultant class in the Factory.
This allows the class to be accessed inside the .kv language file in the
Builder.
'''
cls = type(class_name, parents, attrs)
Factory.register(class_name, cls)
return cls
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.
'''
__metaclass__ = factoryable
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 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()
def __init__(self, **kwargs):
super(Catalog, self).__init__(**kwargs)
self.kv_container = None
from kivy.clock import Clock
Clock.schedule_once(self.show_kv)
def show_kv(self, object, collapsed=None):
'''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 collapsed == "down": # a tabbed panel was clicked, not an accordion
object = object.content.children[0]
collapsed = False
if collapsed is False and hasattr(object, "kv_container"):
with open(object.kv_container.kv_file) as file:
self.language_box.background_color = (1, 1, 1, 1)
self.language_box.readonly = False
self.language_box.text = file.read()
self.kv_container = object.kv_container
else:
self.language_box.background_color = (1, 1, 1, .5)
self.language_box.text = ""
self.language_box.readonly = True
self.kv_container = None
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.'''
if self.kv_container:
try:
parser = Parser(content=self.language_box.text.encode('utf8'))
self.kv_container.clear_widgets()
widget = Factory.get(parser.root.name)()
Builder._apply_rule(widget, parser.root, parser.root)
self.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()