'''Kivy Language ============= The Kivy language is a language dedicated to describing user interface and interactions. You could compare this language to Qt's QML (http://qt.nokia.com), but we included new concepts such as rule definitions (which are somewhat akin to what you may know from CSS), templating and so on. .. versionchanged:: 1.7.0 The Builder doesn't execute canvas expressions in realtime anymore. It will pack all the expressions that need to be executed first and execute them after dispatching input, just before drawing the frame. If you want to force the execution of canvas drawing, just call :meth:`Builder.sync `. An experimental profiling tool for the kv lang is also included. You can activate it by setting the environment variable `KIVY_PROFILE_LANG=1`. It will then generate an html file named `builder_stats.html`. Overview -------- The language consists of several constructs that you can use: Rules A rule is similar to a CSS rule. A rule applies to specific widgets (or classes thereof) in your widget tree and modifies them in a certain way. You can use rules to specify interactive behaviour or use them to add graphical representations of the widgets they apply to. You can target a specific class of widgets (similar to the CSS concept of a *class*) by using the ``cls`` attribute (e.g. ``cls=MyTestWidget``). A Root Widget You can use the language to create your entire user interface. A kv file must contain only one root widget at most. Dynamic Classes *(introduced in version 1.7.0)* Dynamic classes let you create new widgets and rules on-the-fly, without any Python declaration. Templates (deprecated) *(introduced in version 1.0.5, deprecated from version 1.7.0)* Templates were used to populate parts of an application, such as styling the content of a list (e.g. icon on the left, text on the right). They are now deprecated by dynamic classes. Syntax of a kv File ------------------- .. highlight:: kv A Kivy language file must have ``.kv`` as filename extension. The content of the file should always start with the Kivy header, where `version` must be replaced with the Kivy language version you're using. For now, use 1.0:: #:kivy `1.0` # content here The `content` can contain rule definitions, a root widget, dynamic class definitions and templates:: # Syntax of a rule definition. Note that several Rules can share the same # definition (as in CSS). Note the braces: they are part of the definition. : # .. definitions .. : # .. definitions .. # Syntax for creating a root widget RootClassName: # .. definitions .. # Syntax for creating a dynamic class : # .. definitions .. # Syntax for create a template [TemplateName@BaseClass1,BaseClass2]: # .. definitions .. Regardless of whether it's a rule, root widget, dynamic class or template you're defining, the definition should look like this:: # With the braces it's a rule. Without them, it's a root widget. : prop1: value1 prop2: value2 canvas: CanvasInstruction1: canvasprop1: value1 CanvasInstruction2: canvasprop2: value2 AnotherClass: prop3: value1 Here `prop1` and `prop2` are the properties of `ClassName` and `prop3` is the property of `AnotherClass`. If the widget doesn't have a property with the given name, an :class:`~kivy.properties.ObjectProperty` will be automatically created and added to the widget. `AnotherClass` will be created and added as a child of the `ClassName` instance. - The indentation is important and must be consistent. The spacing must be a multiple of the number of spaces used on the first indented line. Spaces are encouraged: mixing tabs and spaces is not recommended. - The value of a property must be given on a single line (for now at least). - Keep class names capitalized to avoid syntax errors. - The `canvas` property is special: you can put graphics instructions in it to create a graphical representation of the current class. Here is a simple example of a kv file that contains a root widget:: #:kivy 1.0 Button: text: 'Hello world' .. versionchanged:: 1.7.0 The indentation is not limited to 4 spaces anymore. The spacing must be a multiple of the number of spaces used on the first indented line. Both the :meth:`~BuilderBase.load_file` and the :meth:`~BuilderBase.load_string` methods return the root widget defined in your kv file/string. They will also add any class and template definitions to the :class:`~kivy.factory.Factory` for later usage. Value Expressions, on_property Expressions, ids, and Reserved Keywords --------------------------------------------------------------------- When you specify a property's value, the value is evaluated as a Python expression. This expression can be static or dynamic, which means that the value can use the values of other properties using reserved keywords. self The keyword self references the "current widget instance":: Button: text: 'My state is %s' % self.state root This keyword is available only in rule definitions and represents the root widget of the rule (the first instance of the rule):: : custom: 'Hello world' Button: text: root.custom app This keyword always refers to your app instance. It's equivalent to a call to :meth:`kivy.app.App.get_running_app` in Python. :: Label: text: app.name args This keyword is available in on_ callbacks. It refers to the arguments passed to the callback. :: TextInput: on_focus: self.insert_text("Focus" if args[1] else "No focus") .. kv-lang-ids: ids ~~~ Class definitions may contain ids which can be used as a keywords::: : Button: id: btn1 Button: text: 'The state of the other button is %s' % btn1.state Please note that the `id` will not be available in the widget instance: it is used exclusively for external references. `id` is a weakref to the widget, and not the widget itself. The widget itself can be accessed with `.__self__` (`btn1.__self__` in this case). When the kv file is processed, weakrefs to all the widgets tagged with ids are added to the root widget's `ids` dictionary. In other words, following on from the example above, the buttons state could also be accessed as follows: .. code-block:: python widget = MyWidget() state = widget.ids["btn1"].state # Or, as an alternative syntax, state = widget.ids.btn1.state Note that the outermost widget applies the kv rules to all its inner widgets before any other rules are applied. This means if an inner widget contains ids, these ids may not be available during the inner widget's `__init__` function. Valid expressons ~~~~~~~~~~~~~~~~ There are two places that accept python statements in a kv file: after a property, which assigns to the property the result of the expression (such as the text of a button as shown above) and after a on_property, which executes the statement when the property is updated (such as on_state). In the former case, the `expression `_ can only span a single line, cannot be extended to multiple lines using newline escaping, and must return a value. An example of a valid expression is ``text: self.state and ('up' if self.state == 'normal' else 'down')``. In the latter case, multiple single line statements are valid, including those that escape their newline, as long as they don't add an indentation level. Examples of valid statements are: .. code-block:: python on_press: if self.state == 'normal': print('normal') on_state: if self.state == 'normal': print('normal') else: print('down') if self.state == 'normal': \\ print('multiline normal') for i in range(10): print(i) print([1,2,3,4, 5,6,7]) An example of a invalid statement: .. code-block:: python on_state: if self.state == 'normal': print('normal') Relation Between Values and Properties -------------------------------------- When you use the Kivy language, you might notice that we do some work behind the scenes to automatically make things work properly. You should know that :doc:`api-kivy.properties` implement the `Observer Design Pattern `_. That means that you can bind your own function to be called when the value of a property changes (i.e. you passively `observe` the property for potential changes). The Kivy language detects properties in your `value` expression and will create create callbacks to automatically update the property via your expression when changes occur. Here's a simple example that demonstrates this behaviour:: Button: text: str(self.state) In this example, the parser detects that `self.state` is a dynamic value (a property). The :attr:`~kivy.uix.button.Button.state` property of the button can change at any moment (when the user touches it). We now want this button to display its own state as text, even as the state changes. To do this, we use the state property of the Button and use it in the value expression for the button's `text` property, which controls what text is displayed on the button (We also convert the state to a string representation). Now, whenever the button state changes, the text property will be updated automatically. Remember: The value is a python expression! That means that you can do something more interesting like:: Button: text: 'Plop world' if self.state == 'normal' else 'Release me!' The Button text changes with the state of the button. By default, the button text will be 'Plop world', but when the button is being pressed, the text will change to 'Release me!'. More precisely, the kivy language parser detects all substrings of the form `X.a.b` where `X` is `self` or `root` or `app` or a known id, and `a` and `b` are properties: it then adds the appropriate dependencies to cause the the constraint to be reevaluated whenever something changes. For example, this works exactly as expected:: : beta: self.a.b[self.c.d] However, due to limitations in the parser which hopefully may be lifted in the future, the following doesn't work:: : beta: self.a.b[self.c.d].e.f indeed the `.e.f` part is not recognized because it doesn't follow the expected pattern, and so, does not result in an appropriate dependency being setup. Instead, an intermediate property should be introduced to allow the following constraint:: : alpha: self.a.b[self.c.d] beta: self.alpha.e.f In addition, properties in python f-strings are also not yet supported:: : text: f"I want to use {self.a} in property" Instead, the ``format()`` method should be used:: : text: "I want to use {} in property".format(self.a) Graphical Instructions ---------------------- The graphical instructions are a special part of the Kivy language. They are handled by the 'canvas' property definition:: Widget: canvas: Color: rgb: (1, 1, 1) Rectangle: size: self.size pos: self.pos All the classes added inside the canvas property must be derived from the :class:`~kivy.graphics.Instruction` class. You cannot put any Widget class inside the canvas property (as that would not make sense because a widget is not a graphics instruction). If you want to do theming, you'll have the same question as in CSS: which rules have been executed first? In our case, the rules are executed in processing order (i.e. top-down). If you want to change how Buttons are rendered, you can create your own kv file and add something like this::