Source

kivy-catalog / main.py

Full commit
Dusty Phillips aeb1d7a 
Dusty Phillips 2b6e69a 

Dusty Phillips b414e68 
Dusty Phillips 5b2091a 
Dusty Phillips 2b6e69a 
Dusty Phillips b414e68 



Dusty Phillips 3674d0e 

Dusty Phillips aeb1d7a 

Dusty Phillips 9b271f9 
Dusty Phillips 8c7428d 
Dusty Phillips f9f98ce 









Dusty Phillips afa9993 
Dusty Phillips e5830ef 







Dusty Phillips f9f98ce 

Dusty Phillips 8c7428d 
Dusty Phillips 3ce3f3e 
Dusty Phillips 8c7428d 
Dusty Phillips afa9993 


Dusty Phillips 5b2091a 
Dusty Phillips 9244966 

Dusty Phillips e5830ef 
Dusty Phillips aeb1d7a 

Dusty Phillips 9244966 
Dusty Phillips 9b271f9 
Dusty Phillips 3674d0e 

Dusty Phillips 3ce3f3e 

Dusty Phillips 5b2091a 
Dusty Phillips e5830ef 



Dusty Phillips 890c541 












Dusty Phillips e5830ef 
Dusty Phillips 5b2091a 
Dusty Phillips 9b271f9 
Dusty Phillips 71cf7f4 



Dusty Phillips 92880b0 
Dusty Phillips e5830ef 


Dusty Phillips 43d52c7 


Dusty Phillips 8c7428d 
Dusty Phillips 43d52c7 
Dusty Phillips 8c7428d 
Dusty Phillips 5b2091a 
Dusty Phillips 71cf7f4 
Dusty Phillips 5b2091a 

Dusty Phillips 71cf7f4 

Dusty Phillips b5023be 
Dusty Phillips e5830ef 



Dusty Phillips 71cf7f4 
Dusty Phillips b414e68 
Dusty Phillips 44577c4 
Dusty Phillips b414e68 
Dusty Phillips afa9993 


Dusty Phillips b414e68 
Dusty Phillips 7737db5 
Dusty Phillips b414e68 



Dusty Phillips 7737db5 
Dusty Phillips c4f09b5 

Dusty Phillips 7737db5 




Dusty Phillips 2b6e69a 


Dusty Phillips e5830ef 

Dusty Phillips 5b2091a 

Dusty Phillips 9b271f9 
Dusty Phillips 2b6e69a 

Dusty Phillips 9b271f9 
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

    def show_kv(self, object, collapsed):
        '''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 not collapsed and hasattr(object, "kv_container"):
            print "called"
            with open(object.kv_container.kv_file) as file:
                self.language_box.text = file.read()
                self.kv_container = object.kv_container
        else:
            self.language_box.text = ""
            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()