Overview

Ezui is designed to easily and/or automatically make interfaces follow the design recommendations in the macOS Human Interface Guidelines. This is an excellent reference for everything from which items to use to how to capitalize text in menu items. Our type designing colleagues and the other designers at Apple have put a lot of thought into this and have given us a great foundation to make interfaces with.

Terminology

The visible UI elements in ezui fall into three categories:

  1. Items are static or interactive objects that users can see.

  2. Containers are items that contain items.

  3. Windows are items that contain containers.

Items are built with descriptions.

Items may, and usually should, be given an identifier.

Items are created with default settings. These settings may be customized with description data given along with the descriptions.

Descriptions, Identifiers and Description Data

Descriptions, identifiers and description data are essential parts of ezui. Everything revolves around understanding them and using them consistently.

Descriptions

Descriptions define the contents of a container, most typically some type of window. These descriptions are created with a text syntax inspired by Markdown. For example, this creates a label, a button, a checkbox, a text field and a slider:

This is a label.
(This is a button.)
[ ] This is a checkbox.
[_ This is a text field. _]
------X------

The text description syntax is defined in the documentation for each item type and there is a cheatsheet for quick reference.

Identifiers

Identifiers are used for various things, including automatic callback linking, getting/setting multiple values for containers and, obviously, item identification. Identifiers are assigned to items in the descriptions. This is done with the @ symbol at the end of the text description. For example, here is the previous set of items with identifiers assigned:

This is a label.
(This is a button.)           @myButton
[ ] This is a checkbox.       @myCheckbox
[_ This is a text field. _]   @myTextField
------X------                 @mySlider

There are some rules for naming identifiers:

Identifier Naming Rules

  1. Identifiers must follow the Python identifier specification. No spaces, must start with _ or a letter, etc.

  2. Identifiers must be unique within the container that contains the item. It is recommended that they be unique across the window that contains the item.

Description Data

Description data allows you to customize the settings of an item. This is done with a dictionary containing overrides of the default settings. The keys and values are specific to each item. For example, here is description data for the previous slider item:

mySliderDescriptionData = dict(
    minValue=-100,
    maxValue=100,
    value=50,
    tickMarks=11
)

Building Windows

To create a window, you pass your descriptions and description data to one of the window constructors. For example, here are the previous items in a fully functional example:

import ezui

class DemoController(ezui.WindowController):

    def build(self):
        content = """
        (This is a button.)           @myButton
        [ ] This is a checkbox.       @myCheckbox
        [_ This is a text field. _]   @myTextField
        ------X------                 @mySlider
        """

        descriptionData = {
            "mySlider" : dict(
                minValue=-100,
                maxValue=100,
                value=50,
                tickMarks=11
            )
        }

        self.w = ezui.EZWindow(
            content=content,
            descriptionData=descriptionData,
            controller=self
        )

    def started(self):
        self.w.open()

    def myButtonCallback(self, sender):
        import pprint
        print("All Values:")
        pprint.pprint(self.w.get())

    def myCheckboxCallback(self, sender):
        value = sender.get()
        slider = self.w.getItem("mySlider")
        if value:
            slider.set(100)
        else:
            slider.set(-100)

    def mySliderCallback(self, sender):
        value = sender.get()
        print(f"Slider Value: {value}")
        checkbox = self.w.getItem("myCheckbox")
        if value > 0:
            checkbox.set(True)
        else:
            checkbox.set(False)

DemoController()

You’ll see that this introduces some new things, like WindowController and callbacks.

WindowController

Every ezui interface should have a controller class that subclasses WindowController. This will establish and terminate all of the necessary functionality at the appropriate times.

Window Constructor

The Window constructor, or other window item constructor, must be called in the build() and it must be retained as self.w. The window must be opened in the started() method.

All window constructors take the following arguments. Other arguments are available to specific window classes.

  • descriptionData This provides the description data discussed above for setting into the items. This must be a dictionary with keys as the item identifier and the value as dictionaries.

  • controller This tells the window which subclass of WindowController is in control of the window. This will be used for connecting callbacks and other operations.

Callbacks

Callbacks are automatically connected from the items to the controller. To make this possible, you define your callbacks as methods of your WindowController subclass with the name pattern identifier + "Callback". For example, the slider above identified with mySlider is automatically connected to the method mySliderCallback.

Getting Items

If you need to directly interact with an item, for example to update the contents, you can get the item with the getItem() method of the container or window that contains the item.

Getting and Setting Values

To get the value from an individual item, use the get method. To set a value into an individual item, use the set method.

To get all the values from a window or container, use the window or container’s getItemValues method. This will return a dictionary with item identifiers as the keys and the item values as the values. To set multiple values into a window or container, use the window or container’s setItemValues method and pass a dictionary with item identifiers as the keys and the item values as the values.

Positioning, Sizing and Spacing

You don’t position items in ezui (except windows if you want them to appear in a specific place). Sizing is mostly automatic as well, with the only exception being items that don’t have inherent sizes. The space between items needs to be defined, but sensible default metrics() are provided so that you don’t have to define a value unless you really want to.


Tip

If any of the above places too many restrictions on your needs, see the Advanced Usage section for details on how almost all of the above can be handled less restrictively.