Interface Layout Specifics

Interface layout has some basic tried-and-true guidelines for designing elegant, highly usable interfaces. That subject is beyond the scope of this help, but we recommend that you find a good book on interface design, pay attention to the layout concept of interfaces you like to use, and beta test with your real users. A good beta tester will let you know pretty quickly when a layout won't work and might be able to tell you what's wrong with it.

So the design is up to you. ALE just helps you achieve it.

The topics in this section include:


Selecting an ALE layout method

ALE offers you three general options for laying out components in your dialog:

You'll probably use a combination of layout methods when you create your interface, simply because interfaces are rarely so simple that a grid or single column of components will do. ALE allows you to use as many of these methods as you like in each section of your ALE file.

Let's look at each method separately.

Grid

Grids are quite simply defined:


   grid(rows, columns, xmin, ymin, xmax, ymax)

  • grid is the method name.

  • rows is the number of rows the grid should have.

  • columns is the number of columns the grid should have.

  • xmin is the point in X where the grid should start, measured in pixels. This is where the grid should be positioned from the left side of the dialog.

  • ymin is the point in Y where the grid should start, measured in pixels. This is where the grid should be positioned from the top of the dialog.

  • xmax is the point in X where the grid should stop. This is where the grid should be positioned from the right side of the dialog.

  • ymax is the point in Y where the grid should stop. This is where the grid should be positioned from the bottom of the dialog.

Components are defined within the grid individually. Each component has its own width, height, X point, Y point, and alignment. Components are not required to be the same size or have the same alignment. The grid merely acts like a table, and each table cell's contents (the component) can be different.

Where are good places to use grids? When you want a console or panel of several buttons that are uniformly placed in rows and columns (e.g., if you wanted to emulate a CD or tape deck console).

Flow

Flows are defined in this way:


   flow(direction, start point, end point, opposing direction centerline)

  • The direction may be either HORIZONTAL or VERTICAL.

  • The start point is the point where the flow should begin. This can be defined as relative to another component or to the dialog itself.

  • The end point is the point where the flow should stop. This can be defined as relative to another component or to the dialog itself.

  • The opposing direction centerline is the line used to center the objects in the opposite direction of their flow.

Good places to use flows are when you have a single column or row of components that are placed one after the other, those components are different sizes, and the column or row should be sized relative to another object.

In our xv example in A Real World ALE File, flows are used liberally to handle rows and columns of buttons that should be aligned and sized relative to other objects. For example, xv has a large listbox which has to its right a column of buttons that are sized to run exactly from the top to the bottom of the listbox. Rather than lay out each button individually, flow allows you to define the flow attributes, define and size one button, and then define the other buttons. Flow automatically handles the rest of the layout.

Free Form Design

The free form design allows you to define and position components individually.

Generally speaking, any component definition outside a flow or grid is free form.


Defining component attributes

If you've already skipped to A Real World ALE File, you've seen the many ways in which component size and position attributes can be defined.

In general, component size and position can be defined:

  • absolutely, in pixels, or using expressions
  • relative to the dialog
  • relative to other components

Defining a component in absolute pixels has the advantage, as well as the disadvantage, that it will never deviate from its size or position no matter how the dialog is resized.


Note: If you define components using absolute values, it may be best to prevent a user's resizing the dialog. If you allow the dialog to be resized, all of the components will congregate in the top left corner of the dialog when the window is dragged larger, leaving blank space to the right and bottom.

Before outlining the many ways that a component can be defined, it may be useful to review the variables used by ALE:

  • w -- Width
  • h -- Height
  • t -- Top
  • b -- Bottom
  • l -- Left
  • r -- Right
  • x -- X Point
  • y -- Y Point

The variables may be used to refer to either the parent container or the components (e.g., w is the dialog's width, and component.w is the component's width. In general, if the variable is not preceeded by the name of a component, it refers to the parent container for each section. You may also refer to the parent component explicitly as in: "parent.w". Also, a component may refer to itself by prepending "this" to an attribute. If your component is called "button1" then "button.w" and "this.w" both refer to the width of the same component, button1.

These variables are used liberally in ALE, whether aligning or sizing the components.


Aligning components

Every component has an X,Y position.

The alignment setting you choose determines how the component is aligned around the X,Y point.

Components' X,Y points can be relative to other components, or relative to the parent container itself.

If you want a component to be aligned in the top left corner of the dialog, with 1 pixel between the top and left edges of the dialog and the component:

  • newcomponent(width, height, 1, 1, LT) -- The component's X,Y point is set to (1,1) of the dialog and it is aligned Left Top, meaning that its left top corner is snapped to (1,1).

If you want a new component to be aligned in Y with an old component and flush with an old component's right side:

  • newcomponent(width, height, oldcomponent.r, oldcomponent.t, LT) -- The new component's X,Y point is the old component's right edge (X) and top edge (Y).

If you want a new component to be aligned in Y with an old component and placed one pixel to its right:

  • newcomponent(width, height, oldcomponent.r + 1, oldcomponent.t, LT) -- The new component has the specified width and height. Its X point is 1 pixel to the right of the old component's right side and its Y point is the same as the old component's top. The new component's top left corner is placed at the X,Y point.

Now let's try aligning the new component with the bottom right corner of the old component:
  • newcomponent(width, height, oldcomponent.r, oldcomponent.b, LT) -- The new component's top left corner is at the bottom right corner of the old component.


Sizing components

Components can be sized:

  • relative to the dialog
  • relative to other components
  • in absolute values

If you want the component to be same size as another component, you can specify this using:

  • newcomponent(oldcomponent.w, oldcomponent.h, X, Y, alignment) -- The width and height of the new component is exactly the same as that of the old component.

  • newcomponent(#, #, X, Y, alignment) -- Use absolute values, in pixels.


Note: The advantage to using relative values rather than absolute values is that if the dialog is resized by the user, the component will be resized to fit the dialog.

Let's say you want a component to be one-fourth of the complete width of dialog in which it resides. It can be done in the following ways:

  • component(pixel_total / 4, height, X, Y, alignment) -- Count the number of pixels of the dialog's width and divide by 4.

  • component(#, height, X, Y, alignment) -- Set the absolute number of pixels for the component's width.

  • component(w / 4, height, X, Y, alignment) -- Use the w variable to refer to the entire width of the dialog and divide by 4.

    or

    component(parent.w / 4, height, X, Y, alignment) -- Use the parent.w variable to refer to the entire width of the parent and divide by 4.


    Note: The button label in this screen shot is abbreviated because the label is longer than the button itself. The button size is determined here by the size of the dialog, which is set in the Java code using setSize(). If the button's size had been chosen to accommodate the label and had been specified in absolute values, then the label would fit the button, but the button would not stretch or contract based on the dialog's size.


Using multiple components

You can define multiple components to be used together. For example, the components on this scanner software dialog are defined individually, but then a container contains the components:

The ALE entry that creates the above example is:


// "Image is..." section with four labels

section imagePanel
{
   flow(VERTICAL, .1 * h, .9 * h, w / 2)
   {
      imageLabel1(p, p, 0, 0, CC)
      imageLabel2(p, p, 0, 0, CC)
      imageLabel3(p, p, 0, 0, CC)
      imageLabel4(p, p, 0, 0, CC)
   }
}

// "Information" panel containing the imagePanel,
// the scan icon, and the scan label

section infoPanel
{
   scan      (w / 6,     this.w, 10, h / 2,        LC)
   scanLabel (p, p,      scan.x, (h + scan.b) / 2, CC)
   imagePanel(3 * w / 4, .75 * h, w - 5, h - 5,    RB)
}

Note here that the section called imagePanel is included in the section called infoPanel.


Note: On a related subject, components that are defined to be stacked are stacked by Java so that the last component defined is placed at the "bottom" of the stack, and the first component defined is placed at the "top".


Defining multiple dialogs

You can define multiple dialogs within the same ALE file since each dialog is, in fact, a "container". Simply give each dialog a separate section, and in your Java code, specify the individual sections as needed.

If the interfaces are complex, you may find it easier to create an ALE file for each dialog.