Introduction to layouts

A layout is a description of how to visually arrange the fields and other data elements in an entry form or a table.

Layouts are one of Lino's important features which it adds to the Django framework. They provide a way to design forms using the Python language and independently of the chosen renderer. Their concept and implementation is fully Luc's work, and we didn't yet find a similar approach in any other framework.

The columns of a table

The simplest occurence of layouts is the column_names attribute of a table, used to define which fields should be displayed as the columns of that table.

Code example (from A Local Exchange Trade System):

class Products(dd.Table):
    ...
    column_names = 'id name providers customers'
    ...

Result:

../../_images/products.png

The layout of a detail window

The next usage of layouts is the detail window, i.e. the window used to display one table row at a time.

You define a detail window by setting the detail_layout attribute of a table. For example:

class Members(dd.Table):
    ...
    detail_layout = """
    id name place email
    OffersByMember DemandsByMember
    """

Result:

../../_images/b.png

Note that the names id, name, place and email in the above example represent single-line entry fields while OffersByMember and DemandsByMember refer to multi-line panels containing a grid.

The insert window

Insert windows are similar to detail windows, but they are used on rows that do not yet exist. The most visible difference is their default size: while detail windows usually take the full screen, insert windows usually are modular pop-up windows.

You define an insert window by setting the insert_layout attribute of a table. For example:

class Members(dd.Table):
    ...
    insert_layout = """
    name place
    email
    """

Result:

../../_images/members_insert.png

Where layouts are being used

Until now we have seen that the following attributes of your tables contain layouts:

There are two other places where Lino uses layouts:

Data elements

The data elements of a normal layout (ColumnsLayout, DetailLayout or InsertLayout), can be:

ParamsLayout are special but similar: their data elements refer to the actor parameters (defined as the parameters attribute of their Actor).

And the data elements of an ActionParamsLayout refer to the action parameters (defined as the parameters attribute of their Action).

The template string

For simple layouts it is enough to specify them just as a string template, as in the examples above. Lino will automatically convert such string templates into instances of ColumnsLayout, DetailLayout, InsertLayout, ParamsLayout or ActionParamsLayout.

A layout template is a string containing words, where each word is the name of a data element.

Panels

A Layout consists of panels. Every layout has at least one panel whose name is main.

When a detail_layout is a string, then Lino replaces this by a DetailLayout instance whose main panel is that string.

Writing layouts as classes

In more complex situations it may be preferrable or even necessary to define your own layout class.

You do this by subclassing DetaiLayout. For example:

class PartnerDetail(dd.DetailLayout):

    main = """
    id name
    description contact
    """

    contact = """
    phone
    email
    url
    """

class Partners(dd.Table):
    ...
    detail_layout = PartnerDetail()

Each panel is a class attribute defined on your subclass, containing a string value to be used as template describing the content of that panel.

It can define more panels whose names may be chosen by the application developer (just don't chose the name window_size which has a special meaning, and don't start your panel names with an underscore because these are reserved for internal use).

Panels are either horizontal or vertical, depending on whether their template contains at least one newline character or not.

Indentation doesn't matter.

If the main panel of a FormLayout is horizontal, ExtJS will render the Layout using as a tabbed main panel. If you want a horizontal main panel instead, just insert a newline somewhere in your main's template. Example:

class NoteLayout(dd.FormLayout):
    left = """
    date type subject
    person company
    body
    """

    right = """
    uploads.UploadsByController
    cal.TasksByController
    """

    # the following will create a tabbed main panel:

    main = "left:60 right:30"

    # to avoid a tabbed main panel, specify:
    main = """
    left:60 right:30
    """