Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save roberto-arista/3a8b66192accde3d700fafb8feb7c80f to your computer and use it in GitHub Desktop.
Save roberto-arista/3a8b66192accde3d700fafb8feb7c80f to your computer and use it in GitHub Desktop.

EZML Syntax Basics

# comment
whitespace has no meaning except single spaces used to separate important things
@ is an identifier
() means button of some sort
[__] means text entry of some sort (except checkbox)
{} means image
- means line
X means selected
~ means disabled
... means there is a submenu
> indicates the nesting level

The basic structure.

import ezui

class Demo(ezui.WindowController):

    def build(self):
        pass

    def started(self):
        pass

    def destroy(self):
        pass

Demo()

Building.

import ezui

class Demo(ezui.WindowController):

    def build(self):
        content = """
        This is a label.
        ——X—— @slider
        (Hello) @button
        """
        descriptionData=dict(
        )
        self.w = ezui.EZWindow(
            content=content,
            descriptionData=descriptionData,
            controller=self
        )

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

Demo()

Notes:

  • Explain that anything unrecognizable falls back to being a label.
  • I now arrange kwargs (and other important wide lines) vertically for easier reading.

Connecting callbacks.

import ezui

class Demo(ezui.WindowController):

    def build(self):
        content = """
        ——X—— @slider
        (Hello) @button
        """
        descriptionData=dict(
        )
        self.w = ezui.EZWindow(
            content=content,
            descriptionData=descriptionData,
            controller=self
        )

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

    def buttonCallback(self, sender):
        print("Hello world!”)

Demo()

Notes:

  • These can be wired manually. It’s possible to do pretty much everything manually if that’s what you want.

Adding description data.

import ezui

class Demo(ezui.WindowController):

    def build(self):
        content = """
        ——X—— @slider
        (Hello) @button
        """
        descriptionData = dict(
            slider=dict(
                minValue=0,
                maxValue=10,
                value=0
            )
        )
        self.w = ezui.EZWindow(
            content=content,
            descriptionData=descriptionData,
            controller=self
        )

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

    def buttonCallback(self, sender):
        print("Hello world!”)

Demo()

Notes:

  • If an unknown key is in a description, the traceback will try to help you see what is wrong and how to fix it.

Getting and setting values.

import ezui

class Demo(ezui.WindowController):

    def build(self):
        content = """
        [X] One @checkbox1
        [ ] Two @checkbox2
        ——X—— @slider
        (Hello World) @button
        """
        descriptionData = dict(
            slider=dict(
                minValue=0,
                maxValue=10,
                value=0
            )
        )
        self.w = ezui.EZWindow(
            content=content,
            descriptionData=descriptionData,
            controller=self
        )

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

    def buttonCallback(self, sender):
        print("Hello world!”)
        print(self.w.getItemValues())
        values = dict(
	          checkbox1=False,
	          checkbox2=True,
	          slider=5
        )
        self.w.setItemValues(values)

Demo()

Getting items directly.

import ezui

class Demo(ezui.WindowController):

    def build(self):
        content = """
        [X] One @checkbox1
        [ ] Two @checkbox2
        ——X—— @slider
        (Hello World) @button
        """
        descriptionData = dict(
            slider=dict(
                minValue=0,
                maxValue=10,
                value=0
            )
        )
        self.w = ezui.EZWindow(
            content=content,
            descriptionData=descriptionData,
            controller=self
        )

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

    def buttonCallback(self, sender):
        print("Hello world!”)
        slider = self.w.getItem("slider")
        print(slider.get())

Demo()

Show storing a reference to an item instead of asking for it repeatedly.

Items.

import ezui

class Demo(ezui.WindowController):

    def build(self):
        content = """
        Label @label
				(PushButton)      @pushButton
				[ ] Checkbox      @checkbox
				( ) Radio 1       @radioButtons
				( ) Radio 2
				---X----------    @slider
				[_TextField _]    @textField
				-----------------
				(PopUpButton ...) @popUpButton
        """
        descriptionData = dict(
            popUpButton=dict(
                popUpButton=dict(
                    items=["A", "B", "C"]
                )
            )
        )
        self.w = ezui.EZWindow(
            content=content,
            descriptionData=descriptionData,
            controller=self
        )

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

Demo()

Special lockups.

import ezui

class Demo(ezui.WindowController):

    def build(self):
        content = """
 				---X--- 123
 				---X--- [_123_]
				[_123_](÷)
				Before [_ABC_] After
        """
        descriptionData = dict(
        )
        self.w = ezui.EZWindow(
            content=content,
            descriptionData=descriptionData,
            controller=self,
            size=(200, "auto")
        )

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

Demo()

TextField options.

(Go through these quickly just to show that the type support is built in.)

import ezui

class DemoController(ezui.WindowController):

    def build(self):
        content = """
        [_String.         _]   @stringTextField
        [_List of strings._]   @stringListTextField
        [_1               _]   @numberTextField
        [_1 2.3 4         _]   @numberListTextField
        [_1               _]   @integerTextField
        [_1.2             _]   @floatTextField
        [_1.2 3.4 5.6     _]   @floatListTextField
        -----
        Leading text. [______] Trailing text.
        -----
        {hare.fill} [______] {tortoise.fill}
        """
        descriptionData = dict(
            stringTextField=dict(
                placeholder="Enter a string.",
                valueType="string"
            ),
            stringListTextField=dict(
                placeholder="Enter a list of strings.",
                valueType="stringList"
            ),
            numberTextField=dict(
                placeholder="Enter a number.",
                valueType="number"
            ),
            numberListTextField=dict(
                placeholder="Enter a list of numbers.",
                valueType="numberList"
            ),
            integerTextField=dict(
                placeholder="Enter an integer.",
                valueType="integer"
            ),
            floatTextField=dict(
                placeholder="Enter a float.",
                valueType="float"
            ),
            floatListTextField = dict(
                placeholder="Enter a list of floats.",
                valueType="floatList"
            )
        )
        self.w = ezui.EZWindow(
            title="Demo",
            size=(300, "auto"),
            content=content,
            descriptionData=descriptionData,
            controller=self
        )

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

    def stringTextFieldCallback(self, sender):
        print(f"stringTextField: {sender.get()} {type(sender.get())}")

    def stringListTextFieldCallback(self, sender):
        print(f"stringListTextField: {sender.get()} {type(sender.get())}")

    def numberTextFieldCallback(self, sender):
        print(f"numberTextField: {sender.get()} {type(sender.get())}")

    def numberListTextFieldCallback(self, sender):
        print(f"numberListTextField: {sender.get()} {type(sender.get())}")

    def integerTextFieldCallback(self, sender):
        print(f"integerTextField: {sender.get()} {type(sender.get())}")

    def integerListTextFieldCallback(self, sender):
        print(f"integerListTextField: {sender.get()} {type(sender.get())}")

    def floatTextFieldCallback(self, sender):
        print(f"floatTextField: {sender.get()} {type(sender.get())}")

    def floatListTextFieldCallback(self, sender):
        print(f"floatListTextField: {sender.get()} {type(sender.get())}")

DemoController()

Table.

import ezui

class Demo(ezui.WindowController):

    def build(self):
        content = """
        |-----| @table
        |     |
        |-----|
        """
        descriptionData = dict(
            table=dict(
                items=[
                    "A",
                    "B",
                    "C"
                ]
            )
        )
        self.w = ezui.EZWindow(
            content=content,
            descriptionData=descriptionData,
            controller=self,
            size=(200, 200)
        )

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

Demo()

Notes:

  • This is vanilla.List2 with more convenience.
  • There are multiple table types depending on where the table is placed in a window. AppKit chooses automatically.

Table with Footer

import ezui

class Demo(ezui.WindowController):

    def build(self):
        content = """
        |-----| @table
        > (+-) @addRemoveButton
        > (Hi...) @popUpButton
        """
        descriptionData = dict(
            table=dict(
                items=[
                    "A",
                    "B",
                    "C"
                ]
            ),
            popUpButton=dict(
                items=[
                    "X",
                    "Y",
                    "Z"
                ]
            )
        )
        self.w = ezui.EZWindow(
            content=content,
            descriptionData=descriptionData,
            controller=self,
            size=(200, 200)
        )

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

    def addRemoveButtonAddCallback(self, sender):
        table = self.w.getItem("table")
        popUpButton = self.w.getItem("popUpButton")
        value = popUpButton.getItems()[popUpButton.get()]
        items = table.get()
        items.append(value)
        table.set(items)

    def addRemoveButtonRemoveCallback(self, sender):
        table = self.w.getItem("table")
        items = table.get()
        for index in reversed(table.getSelectedIndexes()):
            del items[index]
        table.set(items)

Demo()

Notes:

  • We don’t interact with the table contents via the table anymore.
  • I may add some support for common actions (add, remove, duplicate, etc.) so that we don’t have to keep repeating this code.

Table with columns.

import ezui

class Demo(ezui.WindowController):

    def build(self):
        content = """
        |-----------| @table
        | One | Two |
        |-----------|
        |           |
        |-----------|
        """
        descriptionData = dict(
            table=dict(
                columnDescriptions=[
                    dict(
                        identifier="one",
                        title="One"
                    ),
                    dict(
                        identifier="two",
                        title="Two"
                    )
                ],
                items=[
                    dict(one="A", two="B"),
                    dict(one="B", two="C"),
                    dict(one="C", two="D")
                ]
            )
        )
        self.w = ezui.EZWindow(
            content=content,
            descriptionData=descriptionData,
            controller=self,
            size=(300, 200)
        )

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

Demo()

Notes:

  • List2 allows for other item value types than dict. You can put a glyph or font in the list and have specific attributes or methods used for getting/setting values.
  • Drag and drop is significantly improved and more powerful. This is also advanced.

Table item prototype.

import ezui

class Demo(ezui.WindowController):

    def build(self):
        content = """
        |-----------| @table
        | One | Two |
        |-----------|
        |           |
        |-----------|
        > (+-)        @addRemoveButton
        """
        descriptionData = dict(
            table=dict(
                columnDescriptions=[
                    dict(
                        identifier="one",
                        title="One"
                    ),
                    dict(
                        identifier="two",
                        title="Two"
                    )
                ],
                items=[
                    dict(one="A", two="B"),
                    dict(one="B", two="C"),
                    dict(one="C", two="D")
                ],
                itemPrototype=dict(one="N", two="O")
            )
        )
        self.w = ezui.EZWindow(
            content=content,
            descriptionData=descriptionData,
            controller=self,
            size=(300, 200)
        )

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

    def addRemoveButtonAddCallback(self, sender):
        table = self.w.getItem("table")
        item = table.makeItem(one="Y", two="Z")
        items = table.get()
        items.append(item)
        table.set(items)

Demo()

Table with different cell types.

import ezui

class Demo(ezui.WindowController):

    def build(self):
        content = """
        |-------------------| @table
        | One | Two | Three |
        |-------------------|
        | [_] | CCC | X---- |
        |-------------------|
        """
        descriptionData = dict(
            table=dict(
                columnDescriptions=[
                    dict(
                        identifier="one",
                        title="One",
                        cellDescription=dict(
                            cellType="TextField",
                            valueType="integer",
                            valueFallback=0
                        ),
                        editable=True
                    ),
                    dict(
                        identifier="two",
                        title="Two",
                        cellDescription=dict(
                            cellType="ColorWell"
                        ),
                        editable=True
                    ),
                    dict(
                        identifier="three",
                        title="Three",
                        cellDescription=dict(
                            cellType="Slider",
                            cellClassArguments=dict(
                                minValue=0,
                                maxValue=100
                            )
                        ),
                        editable=True
                    )
                ],
                items=[
                    dict(one=1, two=(1, 0, 0, 1), three=0),
                    dict(one=2, two=(0, 1, 0, 1), three=50),
                    dict(one=3, two=(0, 0, 1, 1), three=100),
                ]
            )
        )
        self.w = ezui.EZWindow(
            content=content,
            descriptionData=descriptionData,
            controller=self,
            size=(400, 200)
        )

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

    def tableEditCallback(self, sender):
        print("tableEditCallback")
        items = self.w.getItemValue("table")
        for item in items:
            print(item)
        print("")

Demo()

Table with group rows.

import ezui

class Demo(ezui.WindowController):

    def build(self):
        content = """
        |-----| @table
        |     |
        |-----|
        """
        items = []
        items.append(ezui.TableGroupRow(text="Uppercase"))
        items += list("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
        items.append(ezui.TableGroupRow(text="Lowercase"))
        items += list("abcdefghijklmnopqrstuvwxyz")
        items.append(ezui.TableGroupRow(text="Numbers"))
        items += list("0123456789")
        descriptionData = dict(
            table=dict(
                items=items,
                allowsGroupRows=True
            )
        )
        self.w = ezui.EZWindow(
            content=content,
            descriptionData=descriptionData,
            controller=self,
            size=(200, 200)
        )

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

Demo()

Notes:

  • Group rows can be styled.

Table selection.

import ezui

class Demo(ezui.WindowController):

    def build(self):
        content = """
        |------| @table
        |      |
        |------|
        (Select) @button
        """
        descriptionData = dict(
            table=dict(
                items=[
                    "A",
                    "B",
                    "C"
                ]
            )
        )
        self.w = ezui.EZWindow(
            content=content,
            descriptionData=descriptionData,
            controller=self,
            size=(200, 200)
        )

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

    def tableSelectionCallback(self, sender):
        print("tableSelectionCallback")
        table = sender
        print(table.getSelectedIndexes())
        print(table.getSelectedItems())
        print("")

    def buttonCallback(self, sender):
        table = self.w.getItem("table")
        table.setSelectedIndexes([0, 2])
    

Demo()

Content types.

Colors

Colors can be (r, g, b, a) or NSColor. Using NSColor is useful because the colors automatically change to support dark/light mode, accessibility and vibrancy.

https://developer.apple.com/design/human-interface-guidelines/foundations/color https://developer.apple.com/documentation/appkit/nscolor/standard_colors?language=objc

import AppKit
import ezui

class Demo(ezui.WindowController):

    def build(self):
        content = """
        * Box @box1
        * Box @box2
        """
        descriptionData = dict(
            box1=dict(
                backgroundColor=(1, 0, 0, 1),
                borderColor=(0, 0, 0, 0),
                height=100
            ),
            box2=dict(
                backgroundColor=AppKit.NSColor.systemRedColor(),
                borderColor=(0, 0, 0, 0),
                height=100
            ),
        )
        self.w = ezui.EZWindow(
            content=content,
            descriptionData=descriptionData,
            controller=self,
            size=(200, "auto")
        )

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

Demo()

Images

We should be using SF Symbols whenever possible. Ezui supports these within EZML {name}. Get the SF Symbols app to see what is available.

https://developer.apple.com/sf-symbols/

Symbols can be colored, have multiple colors, have variations within their contents, match weights, match text styles and more.

import pprint
import AppKit
import ezui

class SymbolDemo(ezui.WindowController):

    def build(self):
        content = """
        = HorizontalStack

        * OneColumnForm @configurationForm
        > : variableValue:
        > ---X--- X @variableValue

        > : style:
        > (Style ...) @style

        > : pointSize:
        > [_50_](÷) @pointSize

        > : weight:
        > (Weight ...) @weight

        > : scale:
        > (Scale ...) @scale

        * VerticalStack
        > default:
        > * Image @imageDefault

        * VerticalStack
        > monochrome
        > * Image @imageMonochrome

        * VerticalStack
        > hierarchical
        > * Image @imageHierarchical

        * VerticalStack
        > palette
        > * Image @imagePalette

        * VerticalStack
        > multicolor
        > * Image @imageMulticolor
        """
        imageWidth = 120
        imageHeight = 120
        descriptionData = dict(
            configurationForm=dict(
                width=150
            ),
            variableValue=dict(
                tickMarks=11,
                minValue=0,
                maxValue=1.0,
                value=0.5,
                stopOnTickMarks=True
            ),
            style=dict(
                width="fill",
                items=[
                    "None",
                    "largeTitle",
                    "title1",
                    "title2",
                    "title3",
                    "headline",
                    "subheadline",
                    "body",
                    "callout",
                    "footnote",
                    "caption1",
                    "caption2"
                ]
            ),
            pointSize=dict(
                value=50,
                minValue=5,
                maxValue=100,
                increment=1,
                valueType="integer"
            ),
            weight=dict(
                width="fill",
                items=[
                    "None",
                    "ultraLight",
                    "thin",
                    "light",
                    "regular",
                    "medium",
                    "semibold",
                    "bold",
                    "heavy",
                    "black"
                ]
            ),
            scale=dict(
                width="fill",
                items=[
                    "None",
                    "small",
                    "medium",
                    "large"
                ]
            ),
            imageDefault=dict(
                width=imageWidth,
                height=imageHeight
            ),
            imageMonochrome=dict(
                width=imageWidth,
                height=imageHeight,
            ),
            imageHierarchical=dict(
                width=imageWidth,
                height=imageHeight,
            ),
            imageMulticolor=dict(
                width=imageWidth,
                height=imageHeight,
            ),
            imagePalette=dict(
                width=imageWidth,
                height=imageHeight,
            ),
        )
        self.w = ezui.EZWindow(
            content=content,
            descriptionData=descriptionData,
            # size=(500, 500),
            # minSize=(200, 200),
            # maxSize=(800, 800),
            controller=self
        )
        self.imageDefault = self.w.getItem("imageDefault")
        self.imageMonochrome = self.w.getItem("imageMonochrome")
        self.imageHierarchical = self.w.getItem("imageHierarchical")
        self.imageMulticolor = self.w.getItem("imageMulticolor")
        self.imagePalette = self.w.getItem("imagePalette")
        self.populateImages()

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

    def configurationFormCallback(self, sender):
        self.populateImages()

    def populateImages(self):
        configuration = self.w.getItem("configurationForm").getItemValues()
        # variableValue
        variableValue = configuration["variableValue"]
        # style
        style = configuration["style"]
        style = self.w.getItem("style").getItems()[style]
        if style == "None":
            style = None
        # pointSize
        pointSize = configuration["pointSize"]
        # weight
        weight = configuration["weight"]
        weight = self.w.getItem("weight").getItems()[weight]
        if weight == "None":
            weight = None
        # scale
        scale = configuration["scale"]
        scale = self.w.getItem("scale").getItems()[scale]
        if scale == "None":
            scale = None
        configuration = dict(
            style=style,
            pointSize=pointSize,
            weight=weight,
            scale=scale
        )

        def config(mode=None):
            config = dict(configuration)
            config["renderingMode"] = mode
            if mode == "hierarchical":
                config["colors"] = [(1, 0, 0, 1)]
            elif mode == "palette":
                config["colors"] = [(0, 0, 1, 1), (0, 1, 0, 1)]
            elif mode == "monochrome":
                config["colors"] = [(1, 0, 0, 1)]
            return config

        image = ezui.makeImage(
            symbolName="chart.bar.doc.horizontal.fill",
            variableValue=variableValue
        )
        multicolorImage = ezui.makeImage(
            symbolName="pc",
            variableValue=variableValue
        )
        self.imageDefault.setImage(imageObject=image)
        self.imageMonochrome.setImage(imageObject=image)
        self.imageHierarchical.setImage(imageObject=image)
        self.imageMulticolor.setImage(imageObject=multicolorImage)
        self.imagePalette.setImage(imageObject=image)

        self.imageDefault.setSymbolConfiguration(**config(None))
        self.imageMonochrome.setSymbolConfiguration(**config("monochrome"))
        self.imageHierarchical.setSymbolConfiguration(**config("hierarchical"))
        self.imageMulticolor.setSymbolConfiguration(**config("multicolor"))
        self.imagePalette.setSymbolConfiguration(**config("palette"))

SymbolDemo()

There are fallbacks for older OS versions if you are concerned about that.

Eventually I’ll add support for custom symbols.

Fonts

This is really complex and, honestly, there are not many good reasons to deviate from the HIG so, change fonts with caution. Use ezui.makeFont if you must do something outside of TextEditor.

Containers

Containers are defined in EZML with * ContainerTypeName @identifier. Always give your container an identifier. > is used to indicate items should be placed in the active container.

Box

import ezui

class Demo(ezui.WindowController):

    def build(self):
        content = """
        * Box
        > (Button)
        > [ ] Checkbox
        """
        descriptionData = dict(
        )
        self.w = ezui.EZWindow(
            content=content,
            descriptionData=descriptionData,
            controller=self,
            size="auto"
        )

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

Demo()

Notes:

  • Don’t use Box like this except for testing.

VerticalStack

The default content type for every container is VerticalStack. It’s sometimes useful to declare it for clarity.

import ezui

class Demo(ezui.WindowController):

    def build(self):
        content = """
        * VerticalStack @stack
        > * Box @box1
        >> Box 1
        > * Box @box2
        >> Box 2
        > * Box @box3
        >> Box 3
        """
        descriptionData = dict(
            box1=dict(
                backgroundColor=(1, 0, 0, 1),
                borderColor=(0, 0, 0, 0),
                height=150
            ),
            box2=dict(
                backgroundColor=(0, 1, 0, 1),
                borderColor=(0, 0, 0, 0),
                height=100
            ),
            box3=dict(
                backgroundColor=(0, 0, 1, 1),
                borderColor=(0, 0, 0, 0),
                height=50
            )
        )
        self.w = ezui.EZWindow(
            content=content,
            descriptionData=descriptionData,
            controller=self,
            size=(200, "auto")
        )

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

Demo()

Notes:

  • There are a lot of options for how things fit into stacks, the spacing, alignment, etc. See the documentation.

HorizontalStack

import ezui

class Demo(ezui.WindowController):

    def build(self):
        content = """
        * HorizontalStack @stack
        > * Box @box1
        >> Box 1
        > * Box @box2
        >> Box 2
        > * Box @box3
        >> Box 3
        """
        descriptionData = dict(
            box1=dict(
                backgroundColor=(1, 0, 0, 1),
                borderColor=(0, 0, 0, 0),
                width=200,
                height=100
            ),
            box2=dict(
                backgroundColor=(0, 1, 0, 1),
                borderColor=(0, 0, 0, 0),
                width=150,
                height=100
            ),
            box3=dict(
                backgroundColor=(0, 0, 1, 1),
                borderColor=(0, 0, 0, 0),
                width=100,
                height=100
            )
        )
        self.w = ezui.EZWindow(
            content=content,
            descriptionData=descriptionData,
            controller=self,
            size="auto"
        )

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

Demo()

Tabs

import ezui

class Demo(ezui.WindowController):

    def build(self):
        content = """
        * Tabs

        > * Tab: One @tab1
        >> This is tab 1.

        > * Tab: Two @tab2
        >> This is tab 2.
        """
        descriptionData = dict(
        )
        self.w = ezui.EZWindow(
            content=content,
            descriptionData=descriptionData,
            controller=self,
            size=(200, 200)
        )

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

Demo()

If a container is the only item side of another container, change the top container type with =.

import ezui

class Demo(ezui.WindowController):

    def build(self):
        content = """
        = Tabs

        * Tab: One @tab1
        > This is tab 1.

        * Tab: Two @tab2
        > This is tab 2.
        """
        descriptionData = dict(
        )
        self.w = ezui.EZWindow(
            content=content,
            descriptionData=descriptionData,
            controller=self,
            size=(200, 200)
        )

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

Demo()

Nesting

import ezui

class Demo(ezui.WindowController):

    def build(self):
        content = """
        = HorizontalStack
        * Box @box1
        * Box @box2 = VerticalStack
        > * Box @box2a
        > * Box @box2b = HorizontalStack
        >> * Box @box2b1
        >> * Box @box2b2
        > * Box @box2c
        * Box @box3
        """
        descriptionData = dict(
            box1=dict(
                backgroundColor=(1, 0, 0, 1),
                borderColor=(0, 0, 0, 0),
                width=100
            ),
            box2=dict(
                backgroundColor=(0, 1, 0, 1),
                borderColor=(0, 0, 0, 0),
                width=200
            ),
            box3=dict(
                backgroundColor=(0, 0, 1, 1),
                borderColor=(0, 0, 0, 0),
                width=300
            ),
            box2a=dict(
                backgroundColor=(1, 1, 1, 1),
                borderColor=(0, 0, 0, 0),
                height=100
            ),
            box2b=dict(
                backgroundColor=(0.5, 0.5, 0.5, 1),
                borderColor=(0, 0, 0, 0),
                height=100
            ),
            box2c=dict(
                backgroundColor=(0, 0, 0, 1),
                borderColor=(0, 0, 0, 0),
                height=100
            ),
            box2b1=dict(
                backgroundColor=(1, 1, 0, 1),
                borderColor=(0, 0, 0, 0)
            ),
            box2b2=dict(
                backgroundColor=(0, 1, 1, 1),
                borderColor=(0, 0, 0, 0)
            ),
        )
        self.w = ezui.EZWindow(
            content=content,
            descriptionData=descriptionData,
            controller=self,
            size="auto"
        )

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

Demo()

Forms

Forms are structured ways to make the most common UI combinations. These can stand on their own or be part of a larger UI.

OneColumnForm

import ezui

class Demo(ezui.WindowController):

    def build(self):
        content = """
        * OneColumnForm @form

        > !§ Section 1

        > : Slider Label:
        > ---X--- @slider

        > : Radio Label:
        > (X) One @radios
        > ( ) Two

        > : Checkboxes Label:
        > [ ] Checkbox 1 @checkbox1
        > [ ] Checkbox 2 @checkbox2

        > !§ Section 2

        > : TextEditor Label:
        > [[__]] @textEditor
        """
        descriptionData = dict(
        )
        self.w = ezui.EZWindow(
            content=content,
            descriptionData=descriptionData,
            controller=self,
            size="auto"
        )

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

    def formCallback(self, sender):
        import pprint
        pprint.pprint(sender.getItemValues())

Demo()

TwoColumnForm

import ezui

class Demo(ezui.WindowController):

    def build(self):
        content = """
        * TwoColumnForm @form

        > !§ Section 1

        > : Slider Label:
        > ---X--- @slider

        > : Radio Label:
        > (X) One @radios
        > ( ) Two

        > : Checkboxes Label:
        > [ ] Checkbox 1 @checkbox1
        > [ ] Checkbox 2 @checkbox2

        > !§ Section 2

        > : TextEditor Label:
        > [[__]] @textEditor
        """
        descriptionData = dict(
            form=dict(
                titleColumnWidth=125,
                itemColumnWidth=200
            ),
            textEditor=dict(
                height=100
            )
        )
        self.w = ezui.EZWindow(
            content=content,
            descriptionData=descriptionData,
            controller=self,
            size="auto"
        )

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

    def formCallback(self, sender):
        import pprint
        pprint.pprint(sender.getItemValues())

Demo()

Windows

EZWindow

import ezui

class Demo(ezui.WindowController):

    def build(self):
        content = """
        Hello.
        """
        descriptionData = dict(
        )
        self.w = ezui.EZWindow(
            content=content,
            descriptionData=descriptionData,
            controller=self,
            size=(200, 200),
            title="Demo"
        )

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

Demo()

EZPanel

import ezui

class Demo(ezui.WindowController):

    def build(self):
        content = """
        Hello.
        """
        descriptionData = dict(
        )
        self.w = ezui.EZPanel(
            content=content,
            descriptionData=descriptionData,
            controller=self,
            size=(200, 200),
            title="Demo"
        )

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

Demo()

EZSheet

import ezui

class Demo(ezui.WindowController):

    def build(self):
        content = """
        (Hello) @helloButton
        """
        descriptionData = dict(
            helloButton=dict(
                width=200
            )
        )
        self.w = ezui.EZWindow(
            content=content,
            descriptionData=descriptionData,
            controller=self,
            size=(200, "auto"),
            title="Demo"
        )

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

    def helloButtonCallback(self, sender):
        DemoSheet(self.w)
        

class DemoSheet(ezui.WindowController):

    def build(self, parent):
        content = """
        Hello.
        """
        descriptionData=dict(
        )
        self.w = ezui.EZSheet(
            content=content,
            descriptionData=descriptionData,
            controller=self,
            parent=parent
        )

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

Demo()

You can specify a footer. If you do, the close button will go away.

import ezui

class Demo(ezui.WindowController):

    def build(self):
        content = """
        (Hello) @helloButton
        """
        descriptionData = dict(
            helloButton=dict(
                width=200
            )
        )
        self.w = ezui.EZWindow(
            content=content,
            descriptionData=descriptionData,
            controller=self,
            size=(200, "auto"),
            title="Demo"
        )

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

    def helloButtonCallback(self, sender):
        DemoSheet(self)
        

class DemoSheet(ezui.WindowController):

    def build(self, parent):
        content = """
        Hello.
        ======
        (Nope) @nopeButton
        (Done) @doneButton
        """
        descriptionData=dict(
        )
        self.w = ezui.EZSheet(
            content=content,
            descriptionData=descriptionData,
            controller=self,
            parent=parent.w
        )

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

    def doneButtonCallback(self, sender):
        self.w.close()

Demo()

EZPopUp

from mojo.UI import CurrentGlyphWindow
import ezui

class Demo(ezui.WindowController):

    def build(self):
        content = """
        Hello.
        """
        descriptionData = dict(
        )
        self.w = ezui.EZPopUp(
            content=content,
            descriptionData=descriptionData,
            controller=self,
            size=(200, 200),
            parent=CurrentGlyphWindow().w
            
        )

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

Demo()

WindowController

These behave like the defconAppKit window controller. They may gain more features in the future.

Mixing with subscriber.

from mojo.subscriber import Subscriber
from mojo.roboFont import CurrentGlyph
import ezui

class Demo(Subscriber, ezui.WindowController):

    debug = True

    def build(self):
        content = """
        The current glyph is: ? @label
        """
        descriptionData = dict(
            label=dict(
                width="fill"
            )
        )
        self.w = ezui.EZPanel(
            content=content,
            descriptionData=descriptionData,
            controller=self,
            size=(300, "auto")
        )

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

    def updateText(self):
        glyph = CurrentGlyph()
        if glyph is None:
            name = "<none>"
        else:
            name = glyph.name
        text = f"The current glyph is: {name}"
        self.w.setItemValues(dict(label=text))

    def roboFontDidSwitchCurrentGlyph(self, info):
        self.updateText()    

Demo()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment