These powerful features include:
ALE lets you define reusable variables within a section.
Suppose you want to define a gap between a set of buttons. You might
use the following in your ALE file to accomplish this:
section main
{
button1(p, p, 10, 10, LT)
button2(p, p, button1.r + 10, 10, LT)
button3(p, p, button2.r + 10, 10, LT)
}
As an alternative, using the define feature, you could recode that section as
section main { define { TOP = 10; GAP = 10; } button1(p, p, $GAP, $TOP, LT) button2(p, p, button1.r + $GAP, $TOP, LT) button3(p, p, button2.r + $GAP, $TOP, LT) }
This feature allows you to reuse common values and expressions within your component definitions. If you decide to change the gap size to 20 pixels, modifying the GAP entry to read "GAP = 20" would automatically update the layout of your dialog.
You can also define one value in terms of another:
section main { define { VALUE1 = 5; VALUE2 = $VALUE1 * 4; VALUE3 = $VALUE1 + $VALUE2; } }
There are a few caveats:
Here is some sample code demonstrating this feature and the obligatory screen shot:
import java.awt.*; import java.awt.event.*; import com.sun.java.swing.*; import jfd.ale.*; import java.lang.reflect.Field; public class define extends JFrame implements FieldToComponentMapper { private JButton button1 = null; private JButton button2 = null; private JButton button3 = null; private static final String array[] = { "section main", "{", " define", " {", " X_VALUE = w / 2;", " Y_VALUE = h / 4;", " }", "", " button1(p, p, $X_VALUE, $Y_VALUE, CC)", " button2(p, p, $X_VALUE, 2 * $Y_VALUE, CC)", " button3(p, p, $X_VALUE, 3 * $Y_VALUE, CC)", "}" }; public define() throws Exception { addWindowListener( new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } } ); button1 = new JButton("One"); button2 = new JButton("Two"); button3 = new JButton("Three"); ALE.brew(array, "main", this, getContentPane()); setSize(200, 200); show(); } public Component mapToComponent(Field f) throws Exception { return((Component)f.get(this)); } public static void main(String args[]) throws Exception { new define(); } }
ALE also gives you the ability to specify components' sizes or locations
in terms of external method calls.
Suppose you have three buttons and you want to ensure that all the buttons
are the same width. By observation, you can determine which button would
be the widest and set the other buttons' widths to match, as in:
section main
{
button1(p, p, w / 2, h / 4)
button2(p, button1.w, w / 2, 2 * h / 4)
button3(p, button1.w, w / 2, 3 * h / 4)
}
But this solution isn't optimal. If you change your Java code so that button2 becomes the widest button, all the buttons are still sized to button1's size. Also, with internationalization there may be no easy way to predict which of the buttons will be the largest.
ALE lets you use external methods in place of actual values in the ALE file. The above section (using this external method approach) would look like:
section main { button1(p, getMaxButtonWidth(), w / 2, h / 4) button2(p, button1.w, w / 2, 2 * h / 4) button3(p, button1.w, w / 2, 3 * h / 4) }
ALE will use Java's reflection mechanism to call the method whose name you supply. There are a few stipulations, the method to be called must:
The method must also reside within the class whose "this pointer" you supply as ALE.brew's third parameter. Here is a complete example using embedded (rather than external) layout information.
import jfd.ale.*; import java.awt.*; import java.awt.event.*; public class ExternalMethodAWT extends Frame implements FieldToComponentMapper { private Button button1 = null; private Button button2 = null; private Button button3 = null; private static final String array[] = { "section main", "{", " button1(getMaxButtonWidth(), p, w / 2, h / 4, CC)", " button2(button1.w, p, w / 2, h / 2, CC)", " button3(button1.w, p, w / 2, 3 * h / 4, CC)", "}", }; public ExternalMethodAWT() throws Exception { addWindowListener( new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } } ); button1 = new Button("short"); button2 = new Button("a bit longer"); button3 = new Button("a fairly long button"); ALE.brew(array, "main", this, this); setSize(640, 480); show(); } public double getMaxButtonWidth() { Dimension d = button1.getPreferredSize(); double max = d.width; d = button2.getPreferredSize(); if(d.width > max) max = d.width; d = button3.getPreferredSize(); if(d.width > max) max = d.width; return(max); } public Component mapToComponent(java.lang.reflect.Field f) throws Exception { return((Component)f.get(this)); } public static void main(String args[]) throws Exception { new ExternalMethodAWT(); } }
Here is a screenshot that shows what the resulting dialog would look like
As a final note, external methods can be used anywhere a value or component attribute would be used in your ALE file. As an example:
section main { button1(p, getMaxButtonWidth(), w / 2, h / 4) button2(p, 2 * getValue1(), w / 2, 2 * h / 4) button3(p, getValue2() + getValue3()) / 3, w / 2, 3 * h / 4) }