Controllers

Controllers do the work of converting ezui instructions into user-facing objects.

To use ezui, your ezui content must be defined in a subclass of one of these controllers. The controller classes will make the connections between your code and the user-facing objects. You implement your interface construction and deconstruction in a standard series of methods:

  1. build This will be called when it is time to build the interface components. This method is required.

  2. started This will be called when the interface is presented to the user. This method is optional.

  3. destroy This will be called when the interface is destroyed. This method is optional.

The controllers listed here are fully compatible with Subscriber defined in mojo.subscriber. When using these controllers with Subscriber, you must use the class order Subscriber, OneOfTheControllerClasses. If the order is flipped, the Subscriber initialization will not be done properly and your subscription methods will not be called when events take place.

WindowController

class ezui.WindowController(*args, **kwargs)

A controller for windows.

import ezui

class DemoController(ezui.WindowController):

    def build(self):
        content = """
        (Button) @button
        [_Text_] @textField
        """
        self.w = ezui.EZWindow(
            title="Demo",
            content=content,
            controller=self
        )

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

    def buttonCallback(self, sender):
        print("The button was pushed.")

    def textFieldCallback(self, sender):
        print("The text field was edited.")

DemoController()
startProgress(text=None, maxValue=None, parent=None)

Start a progress bar. This returns an instance of ProgressWindow.

text Text to show. Optional.

maxValue The maximum value for the bar. If this is None the bar will show a looping animation.

parent A parent window to attach the progress window to. Optional.

import AppKit
import ezui

class DemoController(ezui.WindowController):

    def build(self):
        content = """
        (startProgress) @startProgressButton
        """
        self.w = ezui.EZWindow(
            title="Demo",
            size=("auto"),
            content=content,
            controller=self
        )

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

    def startProgressButtonCallback(self, sender):
        self.progressWindow = self.startProgress(
            text="Optional text.",
            maxValue=20,
            parent=self.getWindow()
        )
        self.progressCount = 0
        self.timer = AppKit.NSTimer.scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_(
            0.25,
            self,
            "_incrementProgressBar:",
            None,
            True
        )

    def _incrementProgressBar_(self, timer):
        if self.progressCount == 20:
            self.timer.invalidate()
            self.progressWindow.close()
            self.progressWindow = None
        else:
            self.progressWindow.increment()
            self.progressCount += 1

DemoController()
showMessage(messageText, informativeText='', callback=None, alertStyle='informational', icon=None, helpCallback=None)

Show a message.

messageText A short message.

informativeText A complete description. Optional.

alertStyle The style for the alert. Optional. Options:

  • "informational"

  • "critical"

callback A function to be called when the message is closed.

icon A NSImage to display instead of the default icon. Optional.

helpCallback A callback to be called when the help button is pressed.

import ezui

class DemoController(ezui.WindowController):

    def build(self):
        content = """
        (showMessage) @showMessageButton
        """
        self.w = ezui.EZWindow(
            title="Demo",
            size=("auto"),
            content=content,
            controller=self
        )

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

    def showMessageButtonCallback(self, sender):
        self.showMessage(
            messageText="This is message text.",
            informativeText="This is optional informative text.",
            helpCallback=self.helpButtonCallback
        )

    def helpButtonCallback(self):
        print("The help button was pressed.")

DemoController()
showAsk(messageText, buttonTitles, informativeText='', callback=None, alertStyle='informational', icon=None, helpCallback=None)

Show a dialog with options for the user to choose from.

messageText A short message.

buttonTitles A list of button titles. These are formatted as dicts with the following structure:

{
    "title" : "Text to be displayed.",
    "returnCode" : "Value to be returned by the button."
}

informativeText A complete description. Optional.

alertStyle The style for the alert. Optional. Options:

  • "informational"

  • "critical"

callback A function to be called when the message is closed.

icon A NSImage to display instead of the default icon. Optional.

helpCallback A callback to be called when the help button is pressed.

import ezui

class DemoController(ezui.WindowController):

    def build(self):
        content = """
        (showAsk) @showAskButton
        """
        self.w = ezui.EZWindow(
            title="Demo",
            size=("auto"),
            content=content,
            controller=self
        )

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

    def showAskButtonCallback(self, sender):
        self.showAsk(
            messageText="This is message text.",
            informativeText="This is optional informative text.",
            buttonTitles=[
                dict(title="A?", returnCode="A"),
                dict(title="B?", returnCode="B"),
                dict(title="C?", returnCode="C")
            ],
            callback=self.showAskResultCallback,
            helpCallback=self.helpButtonCallback
        )

    def showAskResultCallback(self, value):
        print(f"showAsk result: {value}")

    def helpButtonCallback(self):
        print("The help button was pressed.")

DemoController()
showAskYesNo(messageText, informativeText='', callback=None, alertStyle='informational', icon=None, helpCallback=None)

Show a dialog with options “Yes” and “No” options for the user to choose from.

messageText A short message.

informativeText A complete description. Optional.

alertStyle The style for the alert. Optional. Options:

  • "informational"

  • "critical"

callback A function to be called when the message is closed.

icon A NSImage to display instead of the default icon. Optional.

helpCallback A callback to be called when the help button is pressed.

import ezui

class DemoController(ezui.WindowController):

    def build(self):
        content = """
        (showAskYesNo) @showAskYesNoButton
        """
        self.w = ezui.EZWindow(
            title="Demo",
            size=("auto"),
            content=content,
            controller=self
        )

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

    def showAskYesNoButtonCallback(self, sender):
        self.showAskYesNo(
            messageText="This is message text.",
            informativeText="This is optional informative text.",
            callback=self.showAskYesNoResultCallback,
            helpCallback=self.helpButtonCallback
        )

    def showAskYesNoResultCallback(self, value):
        print(f"showAskYesNo result: {value}")

    def helpButtonCallback(self):
        print("The help button was pressed.")

DemoController()
showGetFolder(callback, messageText=None, directory=None, allowsMultipleSelection=False, accessoryView=None, descriptionData={})
import ezui

class DemoController(ezui.WindowController):

    def build(self):
        content = """
        (showGetFolder) @showGetFolderButton
        """
        self.w = ezui.EZWindow(
            title="Demo",
            size=("auto"),
            content=content,
            controller=self
        )

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

    def showGetFolderButtonCallback(self, sender):
        accessoryViewContents = """
        = TwoColumnForm

        : Letter:
        (A ...)     @getFolderLetterPopUpButton

        : Number:
        (X) 0       @getFolderNumberRadioButtons
        ( ) 1
        ( ) 2
        """
        accessoryViewDescriptionData = dict(
            getFolderLetterPopUpButton=dict(
                items=["A", "B", "C"]
            )
        )
        self.getFolderLetter = "A"
        self.getFolderNumber = 0
        self.showGetFolder(
            messageText="This is the message text.",
            allowsMultipleSelection=True,
            directory=None,
            accessoryView=accessoryViewContents,
            descriptionData=accessoryViewDescriptionData,
            callback=self.showGetFolderResultCallback
        )

    def getFolderLetterPopUpButtonCallback(self, sender):
        i = sender.get()
        self.getFolderLetter = sender.getItems()[i]

    def getFolderNumberRadioButtonsCallback(self, sender):
        self.getFolderNumber = sender.get()

    def showGetFolderResultCallback(self, result):
        print(f"Path: {result} Letter: {self.getFolderLetter} Number: {self.getFolderNumber}")

DemoController()
showGetFile(callback, fileTypes=[], allowsMultipleSelection=False, messageText=None, directory=None, accessoryView=None, descriptionData={})
import ezui

class DemoController(ezui.WindowController):

    def build(self):
        content = """
        (showGetFile) @showGetFileButton
        """
        self.w = ezui.EZWindow(
            title="Demo",
            size=("auto"),
            content=content,
            controller=self
        )

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

    def showGetFileButtonCallback(self, sender):
        accessoryViewContents = """
        = TwoColumnForm

        : Letter:
        (A ...)     @getFileLetterPopUpButton

        : Number:
        (X) 0       @getFileNumberRadioButtons
        ( ) 1
        ( ) 2
        """
        accessoryViewDescriptionData = dict(
            getFileLetterPopUpButton=dict(
                items=["A", "B", "C"]
            )
        )
        self.getFileLetter = "A"
        self.getFileNumber = 0
        self.showGetFile(
            messageText="This is the message text.",
            fileTypes=["txt", "py"],
            allowsMultipleSelection=True,
            directory=None,
            accessoryView=accessoryViewContents,
            descriptionData=accessoryViewDescriptionData,
            callback=self.showGetFileResultCallback
        )

    def getFileLetterPopUpButtonCallback(self, sender):
        i = sender.get()
        self.getFileLetter = sender.getItems()[i]

    def getFileNumberRadioButtonsCallback(self, sender):
        self.getFileNumber = sender.get()

    def showGetFileResultCallback(self, result):
        print(f"Path: {result} Letter: {self.getFileLetter} Number: {self.getFileNumber}")

DemoController()
showPutFile(callback, fileTypes=[], fileName=None, directory=None, accessoryView=None, descriptionData={}, messageText=None, canCreateDirectories=True)
import ezui

class DemoController(ezui.WindowController):

    def build(self):
        content = """
        (showPutFile) @showPutFileButton
        """
        self.w = ezui.EZWindow(
            title="Demo",
            size=("auto"),
            content=content,
            controller=self
        )

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

    def showPutFileButtonCallback(self, sender):
        accessoryViewContents = """
        = TwoColumnForm

        : Letter:
        (A ...)     @putFileLetterPopUpButton

        : Number:
        (X) 0       @putFileNumberRadioButtons
        ( ) 1
        ( ) 2
        """
        accessoryViewDescriptionData = dict(
            putFileLetterPopUpButton=dict(
                items=["A", "B", "C"]
            )
        )
        self.putFileLetter = "A"
        self.putFileNumber = 0
        self.showPutFile(
            messageText="This is the message text.",
            fileTypes=["abc", "xyz"],
            fileName="Demo.abc",
            canCreateDirectories=True,
            directory=None,
            accessoryView=accessoryViewContents,
            descriptionData=accessoryViewDescriptionData,
            callback=self.showPutFileResultCallback
        )

    def putFileLetterPopUpButtonCallback(self, sender):
        i = sender.get()
        self.putFileLetter = sender.getItems()[i]

    def putFileNumberRadioButtonsCallback(self, sender):
        self.putFileNumber = sender.get()

    def showPutFileResultCallback(self, result):
        print(f"Path: {result} Letter: {self.putFileLetter} Number: {self.putFileNumber}")

DemoController()
getWindow()

Get the window this controller controls.

Subclasses must override this if their window is not located at self.w.

build()

This will be called when the controller is initialized. Subclasses should override this to build the window that this controller controls. The window must not be opened while this method is executing. Open the window in the started method.

started()

This will be called after the build process is completed. Subclasses should override this to open the window that this controller controls and do any other work that can’t be completed in the build method.

destroy()

This will be called when the window is closed. Subclasses may override to tear down anything necessary.

ContainerController

class ezui.ContainerController(*args, **kwargs)

A container controller. This isn’t intended for use on its own. It primarily serves as a superclass for GlyphEditorContainerController and InspectorItemContainerController.

addToParent(parent, position=(0, 0), width=None, height=None, identifier=None)

Add the container this controller controls to parent.

parent A Vanilla object capable of containing views.

position The position of the container within parent. For the time being, position must be expressed in Vanilla style coordinates. Optional.

width The desired width of the container. Optional.

height The desired height of the container. Optional.

identifier A unique identifier for the container. This is currently only used by GlyphEditorContainerController. Optional.

removeFromParent()

Remove the container from the parent.

getContainer()

Get the container this controller controls.

Subclasses must override this if their window is not located at self.v.

build()

This will be called when the controller is initialized. Subclasses should override this to build the container that this controller controls. The container must not be added to the parent view while this method is executing. Do this in the started method.

started()

This will be called after the build process is completed. Subclasses should override this to add the container that this controller controls to the parent view and do any other work that can’t be completed in the build method.

destroy()

This will be called when the container is destroyed. Subclasses may override to tear down anything necessary.

GlyphEditorContainerController

class ezui.GlyphEditorContainerController(*args, **kwargs)

A controller for containers displayed in the Glyph Editor.

class GlyphEditorTest(Subscriber, GlyphEditorContainerController):

    debug = True

    def build(self):
        contents = """
        EZUI in glyph editor.
        (This is a button) @button
        ---X-------------- @slider
        (X) One            @radioButtons
        ( ) Two
        ( ) Three
        |----------------| @table
        |                |
        |----------------|
        """
        descriptionData = dict(
            slider=dict(
                minValue=0,
                maxValue=100,
                value=75
            ),
            table=dict(
                height=100,
                items=[
                    "this",
                    "is",
                    "a",
                    "table"
                ]
            )
        )
        self.v = ezui.VerticalStack(
            contents=contents,
            descriptionData=descriptionData,
            controller=self
        )

    def started(self):
        editor = self.getGlyphEditor()
        self.addToGlyphEditor(
            "com.typesupply.ezuiContainerControllerTest.GlyphEditor",
            position=(50, 50),
            width=150
        )

    def sliderCallback(self, sender):
        print("glyph editor sliderCallback", sender.get())

registerGlyphEditorSubscriber(GlyphEditorTest)
addToGlyphEditor(identifier, position=(0, 0), width=None, height=None)

Add the container this controller controls to the glyph editor assigned to this Subscriber.

parent A Vanilla object capable of containing views.

position The position of the container within the glyph editor. For the time being, position must be expressed in Vanilla style coordinates. Optional.

width The desired width of the container. Optional.

height The desired height of the container. Optional.

identifier A unique identifier for the container.

InspectorItemContainerController

class ezui.InspectorItemContainerController(*args, **kwargs)

A controller for Inspector items.

To control the initial appearance of your item, you may define a inspectorItemData dictionary in yout build method. If you need to override the default behavior, use these keys:

  • index The index at which you want the item inserted into the Inspector.

  • minSize The minimum size for the item.

  • collapsed If the item is initially collapsed.

  • canResize If the item can be resized by the user.

You do not add the item to the Inspector directly. This will be handled automatically for you.

class InspectorTest(Subscriber, InspectorItemContainerController):

debug = True

def build(self):
    contents = /"/"/"
    EZUI in an inspector. view
    (This is a button) @button
    ---X-------------- @slider
    (X) One            @radioButtons
    ( ) Two
    ( ) Three
    |----------------| @table
    |                |
    |----------------|
    /"/"/"
    descriptionData = dict(
        slider=dict(
            minValue=0,
            maxValue=100,
            value=75
        ),
        table=dict(
            height=100,
            items=[
                "this",
                "is",
                "a",
                "table"
            ]
        )
    )
    self.v = ezui.VerticalStack(
        contents=contents,
        descriptionData=descriptionData,
        controller=self
    )
    self.inspectorItemData = dict(
        collapsed=False
    )

def sliderCallback(self, sender):
    print("inspector sliderCallback", sender.get())


registerRoboFontSubscriber(InspectorTest)