Juno(1) Juno(1)
Name
Juno - A double-view constraint-based drawing editor
Syntax
Juno [ options ] [ filename ]
* Introduction
* Command-line Options
* The Current Command
* Editing Through the Drawing View
* Using Point, Text, Template and Set Tools
* User-Interface Declarations
* Using the Special Tools
* The Drawing View
* Using the "Run" Button
* Working with Long-Running Commands
* Folding
* Folding Animations
* Pushing and Popping the Current Command
* The Current Module
* Loading/Saving the Current Module
* The Built-In Modules
* Printing, Previewing, and Producing PostScript
* Producing Pixmaps in GIF Format
* Crash Recovery
* Correcting Mistakes
* Setting Configuration Values
* Interfacing with Zeus
* Compilation and Run-Time Errors
* Environment Variables
* Files
* Bugs
* Shortcomings
* Reporting Bugs
* See Also
Introduction
Juno is a double-view constraint-based drawing editor. It displays a
program and a drawing; the drawing is produced by running the program.
You can modify either the drawing or the program, and Juno will modify
the other to keep them in synch.
Juno is both a program and a programming language. The language has
provisions for solving constraints. Juno makes it easy to specify con-
straints on your drawing.
When you run Juno, the main top-level Juno window appears. To exit the
program, select the Quit command under the Juno-2 menu. The main Juno
window has three important sub-windows:
* the drawing view on the left,
* the current module editor in the upper-right, and
* the current command editor in the lower-right.
The source code in the current module editor and the current command
editor -- together with the code defined in the built-in modules --
comprise your program. Juno renders your drawing by running the current
command. The current command may refer to predicates, functions, and
procedures defined in the current module, or in one of the built-in
modules.
There are two sliding bars separating the three main sub-windows that
you can drag to change their relative sizes. There is also a menu bar
along the top of the window, and a tool palette along the left side.
Initially, the tool palette contains the built-in tools and tools and a
sub-palette for the built-in PS module.
Juno uses the PostScript drawing model. To paint graphics or text in
the drawing, you call procedures defined in the PS module. To paint
graphics, you construct a path composed of straight and curved seg-
ments, and then you stroke or fill the path. To paint text, you call
the procedure PS.Type. See the public view of the PS module for
details.
By default, Juno displays its main window on the display determined by
the DISPLAY environment variable, opens the file named "Untitled.juno"
in the current directory at start-up, and is configured to print your
drawing in portrait orientation. You can alter this behavior using one
of the following command-line switches:
-display Xdisplay
Controls the display on which the main Juno window appears. See
the X(1) man page for a description of the interpretation of the
Xdisplay argument.
-geometry Xgeometry
Controls the initial size and location of the main Juno window.
See the X(1) man page for a description of the interpretation of
the Xgeometry argument.
-config config-file
Juno maintains certain user-configurable values, such as the
fonts used in the user interface and the number of digits to
which real numbers are pretty-printed in the program view. Juno
first sets each of these values to a built-in default. You can
specify new values for these variables in a configuration file.
By default, Juno looks for a file named ".juno-config.sx", first
in the current directory, then in your home directory (as named
by the HOME environment variable). If such a file is found, con-
figuration settings are read from it, overwriting the defaults.
You can specify a different configuration file using the -config
switch. See the section on setting configuration values below for
descriptions of the configuration values and the configuration
file format.
-portrait
When it renders PostScript for your drawing, Juno will render the
drawing in portrait orientation. This is the default.
-landscape
When it renders PostScript for your drawing, Juno will rotate
your drawing by 90 degrees so as to render it in landscape orien-
tation. This is convenient for producing slides for a talk.
-zeus Runs Juno as a server for a single view of the Zeus animation
system. For details, see Interfacing with Zeus below.
The current command must be a Juno command. If this command is a pro-
jection, then it will have the following form:
VAR <variables> IN [ <constraint> -> ] <command> END
In this case, we will find it convenient to refer to the <variables>,
<constraint>, and <command> sections of the current command. The <con-
straint> section in this form is optional. If the current command is
not a projection, then it has no <variables> or <constraint> sections.
Initially, the current command is SKIP, so the drawing is blank.
Changes made through the drawing view change the current command auto-
matically. For example, when you create a new point in the drawing, a
new variable is added to the <variables> section of the current com-
mand. The new variable's initial value is the location of its corre-
sponding point.
To edit through the drawing, you select a tool, and then apply the tool
by clicking, dragging, or typing in the drawing. How you use a tool
depends on the particular tool.
To select a tool, you click on a tool name in any visible tool palette.
The name of the selected tool is highlighted. Only one tool can be
selected at a time; if some tool was already selected when you select a
new tool, the old tool is automatically unselected.
There are four kinds of tools:
* A point tool is a tool associated with a Juno predicate, func-
tion, or procedure, all of whose arguments are points.
* A text tool is a tool associated with a Juno procedure all of
whose arguments are points, except its last argument, which is a
text string.
* A template tool is a tool associated with a Juno procedure that
has no arguments.
* A set tool is a tool associated with a Juno procedure with a sin-
gle argument. These tools get their name from the fact that they
are usually used to set some aspect of the current state, such as
the current fill color or line width. Set tools cannot be
selected. Instead, when you press on a set tool, a menu of possi-
ble arguments appears.
* The built-in tools Create, Freeze, Drag, Adjust, Grid On / Grid
Off, Rel, Rel1, Hor, Ver, Cong, and Para are special. Each of
these tools has its own user interface, and each has its own par-
ticular effect on the current command. See the section Using the
Special Tools below for details.
Juno creates point, text, template, and set tools according to UI
(user-interface) declarations. See the User-Interface Declarations sec-
tion below for more information.
To use a point tool, you simply click in the drawing view. Each time
you click, the point closest to your cursor is selected as the next
point parameter. When you have selected as many points as the total
number of parameters corresponding to the predicate, function, or pro-
cedure associated with the selected point tool, the tool is applied.
You can also use the <SPACE> bar to select points. If you have selected
i points with the current tool, <SPACE> selects the ith point argument
(counting from 0) to the most recently applied tool. This shortcut is
useful for applying the same tool several times in a row. For example,
to express the hints for the points c, d, and e all REL the points a
and b, you would:
1. Click c, click a, click b
2. Click d, type <SPACE>, type <SPACE>
3. Click e, type <SPACE>, type <SPACE>
How the current command is updated when a point tool is applied depends
on the tool. If the point tool is associated with a predicate or func-
tion, then a call to that predicate or function using the point argu-
ments you specified is conjoined onto the end of the <constraint> sec-
tion of the current command. If the point tool is associated with a
procedure, then a call to that procedure using the point arguments you
specified is appended to the <command> section of the current command,
separated from the previous <command> by a semicolon.
Using the <SHIFT> key, you can combine the actions of creating and
selecting a point. If you hold down the <SHIFT> key while clicking with
a point tool, then instead of selecting the existing point nearest your
cursor, Juno creates a new point at the cursor location and selects it.
By default, newly created points are unfrozen. If you hold down the
<OPTION> (or <ALT>) key while creating a new point (either by using the
Create tool or by holding down <SHIFT> as described above), the new
point will be initially frozen.
When you use a point tool, you should select points in the order in
which they appear in the signature of the corresponding predicate,
function, or procedure. For example, suppose you are using the tool
associated with the Juno function Geometry.Mid, which has the following
signature:
FUNC mid = Mid(p, q)
If you then use the Mid tool to select the points a, b, and c (in that
order), Juno will add the constraint a = Geometry.Mid(b, c) to the
current command.
Text tools are very similar to point tools. You select points for all
of the arguments except the last one in exactly the same way. When you
get to the last argument, Juno displays a vertical bar in the drawing
view. You can then type the final text argument. As you type, Juno
displays the text string exactly as it is rendered by the procedure.
Once you are done, hit the <RETURN> key or select another tool to
complete the text. The text is also completed if you do something to
cause another window to grab the keyboard focus. Once the text is
completed, Juno will apply the text tool to the arguments you have
supplied.
The Juno-2 user-interface translates certain text argument keys. In
particular, it translates the <TAB> key to tab character (ASCII code
9), the <ESCAPE> key to the escape character (ASCII code 27), and any
control key by subtracting 128 from the control key's ASCII code. For
example, this means that you can include a newline character in the
text string by typing CTRL-<RETURN> (or equivalently, CTRL-J).
Similarly, you can include a form feed character by typing CTRL-L, or a
tab character by typing <TAB> or CTRL-I. The procedure implementing the
text tool can be written to act on these characters in its argument.
For example, the procedures in the bundled TypeLinesC, TypeLinesL, and
TypeLinesR modules interpret the newline character by starting a new
line of a text block.
Clicking on a template tool replaces the current command with the body
of the procedure associated with the tool. Thus many drawings can be
produced starting from the same template. For example, a template for
drawing a group of slides might draw the border and create control
points for positioning the title and other elements common to many
slides.
When you click on a template tool, the previous contents of the current
command are lost.
Set tools are used to set some aspect of the current state. They are
associated with procedures taking a single argument of arbitrary type.
When you press on the name of a set tool in the tool palette, a menu of
possible arguments appears. When you drag the mouse and select one of
these menu items, a call to the procedure with that argument is
appended to the <command> section of the current command.
You tell Juno which predicates, functions, and procedures in the
current module to create tools for using UI declarations. There are
four legal forms for this declaration:
UI PointTool(<Id>)
This declares the predicate, function, or procedure named <Id> in
the current module to be a point tool. If <Id> names a procedure,
it must have zero out and inout parameters.
UI TextTool(<Id>)
This declares the procedure named <Id> in the current module to
be a text tool. <Id> must name a procedure with at least one in
parameter and zero out and inout parameters. The last parameter
must be a text; the other parameters (if any) must be points.
When the tool is used, the procedure will be called for each
prefix of the string the user types (with a vertical bar
character appended at the right). There will be a final call to
the procedure with the whole string and no vertical bar. In the
first calls, the PostScript state will be automatically saved and
restored, so only the side-effects to the PostScript state made
by the final call will take effect.
UI Template(<Id>)
This declares the procedure named <Id> in the current module to
be a template tool. <Id> must name a procedure with no
parameters.
UI SetTool(<Id>)
This declares the procedure named <Id> in the current module to
be a set tool. <Id> must name a procedure with exactly one in
parameter and zero out and inout parameters.
UI Param(<Id>, <Value>)
This declares <Value> to be a parameter of the set tool <Id>. If
<Id> is the argument to some SetTool user-interface declaration
in the current module, then <Value> will be one of the values
appearing in its menu. <Value> must be either a literal Juno
value or a (possibly qualified) identifier that names a CONST,
VAR, or PROC.
Notice that since <Id> must be an unqualified identifier, the
Param declaration cannot be used to add a parameter to a set tool
in some other module. However, that is not much of a restriction,
since you can easily create a set tool in the current module that
simply invokes the set tool in the other module, and add any
number of parameters to the local set tool.
Here is a list of the special tools and descriptions of how to use
them.
Create
Each time you click with the Create tool, a new point is created
at the cursor location. The name of the point and its initial
location are added to the <variables> section of the current
command. If you don't like the name Juno chooses for a point, you
can edit the name of the corresponding variable in the current
command.
Freeze
Selecting a point with the Freeze tool toggles its state between
unfrozen and frozen. By default, newly created points are
unfrozen. The Juno constraint solver is allowed to change the
locations of unfrozen points, but not the locations of frozen
points. However, you can still move a frozen point yourself using
the Drag and Adjust tools described below.
In the drawing view, the names of unfrozen points are painted in
black, while those of frozen points are painted in an ice-blue
color. In the current command, the initial values of unfrozen
points are only hinted with the near (~) predicate, while those
of frozen points are fixed with the equality (=) predicate.
Since freezing is such a common operation, there is a shortcut
for it that doesn't require you to select the Freeze tool
explicitly: simply right-click to toggle a point's frozen state.
Right mouse clicks are ignored if you are in the middle of
supplying arguments to some tool.
Drag
You can drag a point with the Drag tool. While you drag the
point, Juno solves your constraints and updates the drawing at
each new cursor location. When you are done dragging, the new
location for each point is displayed in the current command.
Of course, since there may be constraints on the point you are
dragging, the point will not necessarily track the mouse. For
example, if you are dragging a point a that is constrained to be
horizontal with a frozen point b, then a will only move
horizontally, even if there is some vertical component to the
mouse motion. In such cases, it is convenient for the cursor to
specify only the horizontal or vertical location of the dragged
point. If you hold down the shift key when you start your drag,
the dragged point is constrained to being horizontal with the
cursor; if you hold down the control or alt key, it is
constrained to being vertical with the cursor.
Since dragging is such a common operation, there is a shortcut
for it that doesn't require you to select the Drag tool
explicitly: simply middle-press to drag a point. The modifier
keys may still be used to constrain the drag as above. Middle
mouse clicks are ignored if you are in the middle of supplying
arguments to some tool.
Adjust
You can also drag a point with the Adjust tool, but Juno does not
continuously solve your constraints and update your drawing as
you drag the point. Instead, it simply solves the constraints and
updates your drawing for the final location of the point. If you
hold down the shift key at the start of the drag, the adjusted
point will only move horizontally; if you hold down the control
or alt key, it will only move vertically.
The Adjust tool differs from the Drag tool in another important
respect. While using the Drag tool, you cannot drag a point to a
location that fails to solve your constraints. This is not the
case with the Adjust tool. For example, if you adjust a frozen
point a that is constrained to be horizontal with another frozen
point b, your current command will produce a run-time error with
overwhelming probability (unless you just happened to adjust a to
a location that was exactly on the horizontal line through b).
Grid On / Grid Off
The Grid On tool turns on a grid determined by two selected
points called the control points of the grid. Selecting the
points a and b as the grid control points activates the grid of
points (x,y) REL (a,b) for all integers x and y. When you apply
the Grid On tool, the name of the tool changes to Grid Off in the
tool palette. If you click on Grid Off, the grid is deactivated,
and the tool name changes back to Grid On.
When the grid is active, Juno paints tiny black dots at the grid
lattice points. Whenever a new point c is created, it is
automatically positioned at the lattice point closest to the
mouse click. The hint for c is represented REL the grid control
points a and b, and c is initially frozen. Note that this does
not imply that c cannot move; only that c's location is
functionally determined by a and b.
When the grid is active, Juno tries to snap adjusted (but not
dragged) points to the nearest lattice point. This rule applies
to the grid control points a and b as well! To move a point to a
non-lattice point, you must drag it instead of adjusting it. If
you want to adjust either a or b to a non-lattice point, you can
also turn the grid off, adjust the point, and then turn the grid
back on.
Rel
The Rel tool converts a hint for a point (such as c ~ (100,150))
into a hint relative to two other points. Selecting the points c,
a, and b (in that order) converts the hint for c to the form c ~
(x,y) REL (a,b). The values for x and y are computed so that the
new hint for c has the same value as the original one. Due to the
semantics of the Juno REL function, the current command will
produce a run-time error if the last two points you select with
the Rel tool are not distinct.
If c already has a hint of the form (x,y) REL (a,b) and you
select the points c, a, and b, the hint for c is converted back
to an equivalent absolute hint of the form (x',y').
Rel1
The Rel1 tool converts a hint for a point into a hint relative to
another point. Selecting the points b and a (in that order)
converts the hint for b to the form b ~ R2.Plus(a,(x,y)). The
values for x and y are computed so that the new hint for b has
the same value as the original one.
If b already has a hint of the form b ~ R2.Plus(a,(x,y)) and you
select the points b and a, the hint for b is converted back to an
equivalent absolute hint of the form (x',y').
Hor, Ver, Cong, Para
You use the Hor, Ver, Cong, and Para tools just like point tools,
but they update the current command to use the syntax of the
built-in Juno predicates HOR, VER, CONG, and PARA.
The Hor and Ver tools both take two (point) arguments. If you
select the points a and b with the Hor or Ver tool, then the
constraint a HOR b or a VER b, respectively, is conjoined to the
end of the <constraint> section of the current command.
The Cong and Para tools both take four (point) arguments. If you
select the points a, b, c, and d with the Cong or Para tool, then
the constraint (a,b) CONG (c,d) or (a,b) PARA (c,d),
respectively, is conjoined to the end of the <constraint> section
of the current command.
The origin of the Juno coordinate system is the center of the drawing
view; x-coordinates increase to the east, and y-coordinates increase to
the north. The units of the Juno coordinate system are PostScript
points, equivalent to 1/72 of an inch.
Normally, Juno maintains the invariant that running the current command
produces the picture in the drawing view. In fact, whenever Juno needs
to repaint the drawing (for example, because you have enlarged the
drawing view window), it simply executes the current command.
However, the drawing view also displays four extra annotations. These
annotations appear on your screen, but not on printed output:
* The drawing view displays the current PostScript path as a thin
red line. This allows you to see the path as you construct it,
before it is stroked or filled.
* Juno displays annotations for the point variables in the current
command. The annotation displayed for each point depends on what
you have selected in the Labels menu. If you have selected
Letters, then Juno displays a small dot at the point location,
along with the name of the variable to the left of and below the
dot. If you have selected Crosses, then a small cross is drawn at
the point location. Usually, these annotations are black, but
they are blue if the point is frozen. If you have selected
Nothing, then no point annotations are shown.
* If the grid has been activated by the built-in Grid On tool, Juno
annotates the drawing view by painting small black dots at the
grid's lattice points.
* Juno displays the current bounding box as a rectangle with a grey
border. The bounding box is part of the PostScript state, and is
set by the PS.SetBBox procedure. See the PS module for details.
Juno performs certain actions before and after running the current
command. Before running the command, it blanks the screen and resets
the PostScript state. After running the current command, it calls
PS.ShowPage to display your drawing, and then it paints the annotations
described above. Notice that global variables in the current module
and built-in modules are not reset to their initial values each time
the current command is run; they maintain their values from run to run.
As stated earlier, Juno usually maintains the invariant that running
the current command produces the picture in the drawing view. However,
there are two cases where the drawing view may not be up-to-date with
the current command.
The first case occurs when you edit either the current command or the
current module directly. If you click in either the current command
editor or the module editor and edit your program, the invariant is
broken.
The second case occurs when you apply a constraint through the drawing
view. Since constraints are typically applied in batches, Juno does
not attempt to update the drawing each time you enter a constraint.
Instead, the constraint is added to the current command, but the
current command is not re-executed. Hence, the drawing become
out-of-date with respect to the current command.
Whenever the drawing becomes out-of-date, clicking on the Run button
re-establishes the invariant by compiling the current command and the
current module, and then running the current command. Even if the
drawing view is up-to-date, Run can be used to re-run the current
command; this is useful if the current command is an animation.
If you are writing a long-running current command such as an animation,
you may want to compile your program and solve its constraints without
actually seeing it run. In that case, you can use the Solve button
instead of the Run button.
The Solve button is like the Run button, except that it compiles and
runs a version of the current command that only solves the current
command's constraints and treats its <commands> section as SKIP. Hence,
except for the annotations described earlier, your drawing will appear
blank when you use Solve. To run the complete current command, use Run
instead. The Solve button is only active when the drawing view is
out-of-date with respect to the current module or current command.
Whenever Juno needs to repaint the drawing view --- for example, when
the drawing view is reshaped or when you drag or adjust a point --- it
runs the current command implicitly. If you are working on a
long-running command, this can be quite tedious.
The Refresh menu lets you configure how the current command should be
run. By default, it is set to Auto Run, which means the current command
is run completely as per the Run button. However, if you set the
refresh mode to Auto Solve, the body of the current command is ignored
as per the Solve button when the drawing is refreshed implicitly. You
will probably want to set the refresh mode to Auto Solve if you are
writing a long-running command such as an animation.
Folding
Juno drawings are typically constructed in a "bottom-up" fashion. You
can write procedures for drawing the smaller components of your
drawing, then procedures that call those procedures to draw larger
components, etc. At each step, you draw a component as a completely
separate drawing, and then you convert the current command for drawing
that component into a procedure. You can also click in a complex
constraint, and then convert it into a predicate. The general operation
of converting the current command into a procedure or predicate for
later re-use is called folding.
When you select Fold... from the Edit menu, Juno displays a dialog box
with a type-in field and two sets of radio buttons. You can specify the
name of the new procedure or predicate by editing the type-in field.
The first set of radio buttons let you choose whether to fold the
current command as a procedure, predicate, or template.
Although the dialog box does not provide a way to fold the current
command into a function, you can easily convert a folded predicate into
a function by editing its signature. If you fold as a procedure or
predicate, the second set of radio buttons lets you specify whether you
want a point tool associated with the folded command or not. If you
fold the current command as a template, you always get a template tool.
Once you click the Ok button in the dialog box, Juno converts the
current command into a procedure or predicate, appends the procedure or
predicate definition to the current module, together with a UI
declaration if appropriate, and replaces the current command by SKIP.
There are two ways in which you can control the parameters of the
procedure or predicate.
The first (and best) way is to type in the dialog box the names of the
points that you want to become arguments, enclosing the list in
parentheses and placing it after the name of the procedure or
predicate. For example, if you have drawn an equilateral triangle with
vertices a, b, and c, you could fold the drawing as a procedure and
type "EqTr(a,b)" in dialog box to specify that the folded procedure is
to have the name "EqTr" and the parameters a and b.
When you fold the current command into a procedure or predicate and
specify which points become parameters, Juno automatically makes the
other points local variables, and automatically gives them appropriate
hints. If there are at least two parameters, the hints for the local
variables are REL to the first two parameters. If there is only one
parameter, the hints are constant offsets from that one parameter. If
there are no parameters, the hints are absolute.
The second way to control the parameters of the procedure or predicate
is to omit the parenthesized list of arguments in the dialog box. This
is usually less convenient than the way described above, but is
supported for backwards compatibility. In this case Juno determines the
parameters to the new procedure or predicate by the following rule:
Those <variables> of the current command that are unhinted or whose
hints are pairs of numbers (i.e., literal point values) become
parameters. All other <variables> of the current command become local
variables of the folded procedure or predicate. These variables
typically have hints expressed REL two other points. Notice that
whether a point becomes a parameter to the procedure/predicate or a
local variable of it depends only on the form of the point's hint, not
on whether it is frozen.
Juno has a built-in Anim module for producing animations. The general
technique for creating an animation is to divide it into scenes,
produce animations for each of the scenes, and then combine those
animations using operators like Anim.Seq and Anim.Co.
To produce each scene, there are two steps:
First, you draw a (still) figure constrained by a slider. Juno has a
built-in Slider module for drawing sliders and constraining points
against the slider's value. You figure should include a call to
Slider.Draw(a,b,c), where the points a and c determine the endpoints of
the slider, and the horizontal position of the point b determines the
location of the slider's thumb.
Second, you fold the figure as an animation using the Fold As
Animation... command in the Edit menu. This brings up a dialogue box in
which you specify the name and arguments of the folded scene (as when
folding a figure into a procedure or predicate) and the names of the
three slider points. If your current command includes a call to
Slider.Draw, then the slider points will be filled in automatically
from it.
Folding an animation produces three procedures in the current module,
and changes the current command into a command which, when run,
animates the figure as if you had dragged the slider smoothly from 0 to
1 over the course of 1 second.
Suppose you typed MoveDot(p,q) in the Fold As Animation... dialogue
box, and specified slider points a,b,c. Then the three procedures
produced would have the following signatures:
PROC MoveDot(p,q,a,b,c);
PROC MoveDotFrame(p,q,t);
PROC an := MoveDotAnim(p,q);
The first of these procedures is like the one produced by folding into
a procedure or predicate with points p and q, but in addition, the
points a, b, and c specify the control points for the slider. The
second procedure draws the animation at time t, for t in the interval
[0,1]. The third procedure produces an animation object that plays the
animation for a duration of 1 second.
Juno also provides a mechanism for pushing the current command so that
you can save your current work in order to create and fold a component
you hadn't anticipated needing. Once you are done folding this new
component, you can pop the current command and resume work where you
left off. You can push any number of commands onto the command stack.
When you select Push Current Command from the Edit menu, Juno wraps a
procedure declaration around the current command and installs this
procedure in the current module. The new procedure has a name of the
form CmdX (where X is a small integer) and takes no arguments. A
procedure in the current module of this form is said to be on the
current command stack, and to have index X. The value chosen for X is
one more than the largest index on the current command stack; the
command with the largest index is the top of the stack. You can
rearrange procedures on the stack simply by renaming their indices and
clicking the Run or Solve button. By default, point tools are not
created for commands on the current command stack.
If the current command is SKIP and you select Pop Current Command from
the Edit menu, Juno replaces the current command with the body of the
procedure on the top of the current command stack, and deletes the
associated procedure declaration from the current module.
The current module must be a legal Juno module. In addition to folded
predicates, functions, and procedures, you can also define global
constants and variables in the current module.
Whenever you click Run or Solve or select one of the commands for
folding, pushing, or popping, the current module is re-compiled. Juno
creates a tool for each point tool, text tool, or set tool in the
current module. The buttons for these tools appear in the tool palette
below the buttons for the special tools. You can use these tools just
like the tools associated with the built-in modules.
Any MODULE declaration in the current module is ignored. Hence, calls
in the current command to tools derived from the current module will be
unqualified.
The contents of the current module and current command correspond to a
disk file. The name of the file is shown at the far right of the menu
bar. Whenever the disk file is out-of-date with respect to the contents
of the current module or current command, the file name is displayed
with a red background.
When you start Juno, it reads the file named filename you specified on
the command line, or the file named Untitled.juno (in the current
working directory) by default. This file is then loaded into the
current module.
If you want to load a different file into the current module, choose
the Open... command from the File menu. This command brings up a
standard dialog box for specifying the name and location of a file. If
you type the name of a new file, Juno creates it for you.
To save the current module, use the Save command under the File menu.
This operation will fail if you don't have write permission on the
corresponding file. Also, Save will result in an error if either the
current module or current command contains a parse or compilation
error.
To save the current module to a file with a new name, choose the Save
As... command under the File menu. This command brings up a standard
dialog box that allows you to specify the new name and/or location for
the file.
To reload the current module from the disk file, overwriting the
current editor contents, choose the Reload command under the File menu.
To clear the current editor contents, choose the Clear All command
under the File menu. Using Clear All immediately followed by Save will
erase the corresponding disk file.
Juno comes bundled with a small collection of built-in modules. One of
these --- the PS module --- is automatically opened when you run Juno.
To open one of the other built-in modules, select the Open Module...
command from the File menu. This command brings up a dialog box with a
list of the available built-in modules. To select a module,
double-click on its name. You can open several built-in modules in a
row. Click the close box in the upper-left corner of the dialog box to
close it.
The currently open modules are displayed in the tool palette. They are
packed into columns as space permits; new columns are started as
necessary to display them all.
The name of each module is actually an anchor of a pop-up menu. By
default, buttons appear below the module name for each tool declared in
the module. The Collapse and Expand commands in the pop-up menu
alternately toggle between displaying these buttons. (Collapsing the
buttons is useful if you want to make room for other modules in the
tool palette.) The Close command in the pop-up menu closes the module
and removes it from the tool palette altogether.
If you choose the Help... command in the pop-up menu, a separate
top-level window appears. The help window displays either a public or
private view of the module. You can switch between the public and
private views of the module using the View menu at the top of the help
window.
Initially, the help window displays a public view of the module. The
public view is like the interface to the module. It does not include
the private declarations in the interface (including private comments),
nor does it include the bodies of public predicates, functions, and
procedures.
The private view of the module is complete. It includes the private
declarations, private comments, and all predicate, function, and
procedure bodies. Certain modules, like the PS, Text, Time, and Unit
modules don't have private views, since their implementations are
hard-coded into the Juno application.
Juno produces PostScript output. You can send your drawing directly to
a PostScript printer or previewer, or you can save it to a file as a
PostScript program.
Juno arranges that the PostScript origin is at the center of the page,
so a figure centered in the drawing window will also be centered on the
printed output. To set the bounding box of the PostScript output, your
current command should call the procedure PS.SetBBox. By default, the
bounding box is the size of a full 8-1/2 by 11 inch page, or 11 by
8-1/2 if you ran Juno with the -landscape switch.
If you select Print from the File menu, your drawing is printed on the
printer named by your PRINTER environment variable. The header page is
labeled "Juno Output". If you select Preview from the File menu, your
drawing is previewed with the PostScript previewer psview(1).
You can also save the PostScript for your drawing to a file. If you
select Save PostScript, the PostScript is written to a file with the
same name as the current module, but with ps as its extension. If you
select Save PostScript As... from the File menu, a dialog box pops up
that allows you to specify a different name for the PostScript file.
What you see on the screen is not exactly what you get when you print
your Juno drawing on a printer. Here are the known dissimilarities:
* The screen fonts and the printer fonts may have slightly
different sizes. However, the PS.StringWidth and PS.FontHeight
procedures return different values for screen fonts than for
printer fonts, so if you make calculations based on their
results, your drawing will be rendered correctly on both the
screen and the printer.
* Due to a feature of the X window system, a sub-path whose start
and end points are coincident will appear closed on the screen,
even if it is an open sub-path. Do not rely on point coincidence
to produce closed sub-paths; instead, use the PS.Close procedure
to close sub-paths explicitly.
* When stroking a path with mitered joints, any joint with a small
enough joint angle is rendered as a beveled joint. This cut-off
angle may differ slightly between the screen and the printer.
* The current line width is rounded to the nearest integer to
determine the width of paths stroked on the screen. On the
printer, the line width is not rounded.
To include a Juno drawing in a web page, you have to convert the
drawing to a pixmap in the GIF file format. There are at least three
ways to do this.
If you have psview(1) installed and are using psview for your
previewer, follow these steps. This process also has the advantage that
it respects any bounding box you may have specified for your figure.
1. Choose Preview from the File menu. This should run the psview(1)
PostScript previewer on your figure. If not, you need to
configure Juno to run psview(1) for its preview command.
2. Scale the Juno drawing to a fixed scale factor such as 2. With
the cursor over the psview window, type "2s". If your drawing is
large, it may not all fit on the screen, in which case you will
have to scale it by a smaller factor. For example, to make it
original size (a scale factor of 1), type "1s".
3. With the cursor still over the psview window, type "^S". This
saves the figure as a pixmap file named "Pixmap###.ppm" in the
current directory, where "###" will be a small integer number
like "001". The exact name of the pixmap file is displayed in the
window's title bar.
4. Convert the pixmap file to a GIF file by using pnm(5) tools in
the following pipeline:
% pnmscale 0.5 Pixmap001.ppm | ppmquant 256 | ppmtogif > fig.gif
Here, the argument "0.5" is the reciprocal of the scale factor
specified to psview in step 2 above. If you used a scale factor
of 1, you don't have to use pnmscale(1). Also, the use of
ppmquant(1) in this pipeline is only necessary if the original
pixmap contains over 256 colors; but it doesn't hurt to use
ppmquant(1) in any case
To produce a GIF file from a general PostScript file, follow these
steps. This method has the disadvantage that is requires an extra
clipping step, even if you specified a bounding box for your drawing.
1. Save your figure in PostScript format using the Save PostScript
command in the File menu.
2. Render the figure with ghostscript using the following command
line (assuming the figure's PostScript is in a file named
"fig.ps"):
% gs -sDEVICE=ppmraw -sOutputFile=fig.ppm -r200 -dNOPAUSE -q -- fig.ps
This produces a pixmap file "fig.ppm" with a resolution of 200
dpi (dots per inch).
3. Scale the figure down and convert it to GIF format:
% pnmscale 0.5 fig.ppm | ppmquant 256 | ppmtogif > fig.gif
The scale factor "0.5" will scale the figure down to 100 dpi. If
you want your final figure to have a different resolution, you
can use a smaller resolution in the previous step, or a smaller
scale factor in this step. For example, using "-r180" in the
previous step and a scale factor of "0.5" will produce a GIF file
with a resolution of 90 dpi.
4. You may now need to crop the resulting "fig.gif" file. One way to
do that is to run xv(1) on the GIF file. This will bring up a
page-size window containing your figure. Select a cropping
rectangle by dragging with your mouse. The size and position of
the cropping rectangle can be fine-tuned using the arrow keys on
your keyboard: the unmodified arrow keys move the rectangle a
pixel at a time, and the shifted arrow keys change the size of
the rectangle by adjusting its east and south borders.
Once you've adjusted the cropping rectangle to your taste,
right-click on the xv window. This will bring up the "xv
controls" window. Click on the button labeled Crop, which will
crop your figure to the cropping rectangle you selected. Then
click on the Save button to save the cropped version of your
figure in GIF format. Finally, click on the Quit button in the
"xv controls" window to exit xv(1).
A third alternative is to take a snapshot of your Juno window using the
X window-dump xwd(1) program. This avoids the step of converting the
figure to PostScript. Here is the recipe:
1. Make sure that point labels have been turned off. Then take a
snapshot of your Juno window by typing:
% sleep 2; xwd -name Juno > fig.xwd
The "sleep 2" command gives you 2 seconds to arrange for the Juno
window to be exposed. You will hear a single beep indicating the
capture has started, followed by a double-beep indicating it is
complete.
2. Run "xv fig.xwd". Crop your figure as described in the last step
of the previous recipe. When you save your file, select
"PBM/PGM/PPM (raw)" as the output format, and change the filename
to "fig.ppm".
3. Convert the file to GIF format by running:
% pnmscale 1 fig.ppm | ppmquant 256 | ppmtogif > fig.gif
To get an anti-aliased result, draw your figure larger than you
want it to appear, and use a value less than 1 in the argument to
pnmscale(1).
In all of these recipes, the pnmscale(1) program is used to produce
anti-aliased figures. The quality of the anti-aliasing will be better
the larger the ratio between the input and output resolutions.
Since GIF is a pixmap file format, the size of your figure when it is
viewed over the web will depend on the resolution of the monitor on
which it is displayed. And monitor resolutions do vary. All Macintosh
monitors have a resolution of 72 dpi, while high-end monitors have
resolutions upwards of 100 dpi. The display resolutions of a PC system
can be anywhere in that range based on the system's display hardware.
If Juno crashes (or if your system crashes) while you are working on a
drawing, don't despair; chances are you have lost only a minute or so
of work. This is because Juno automatically saves the state of your
drawing periodically. After the crash, just run Juno again, giving as
a command line argument the name of the file you were working on when
the crash occurred. For example, if you were working on
"Untitled.juno" when the program crashed, just restart Juno with the
command
Juno Untitled.juno
Juno will notice the checkpoint file and recover from it.
To recover the checkpoint you have to start Juno with the lost file as
a command-line argument; it won't work to start on some other file then
open the lost file.
Juno stores the checkpoint file in the same directory as the file you
are editing. The checkpoint file has the same base name as the file
you are editing, and the extension ".bak". This means that you should
use different base names for your different drawings: if you tried to
store three different drawings in the files "figure", "figure.juno",
and "figure.foo", the checkpoint files for all of them would be in
"figure.bak". (Of course, if you only edit them one at a time, it
won't make any difference that they share a checkpoint file). If you
don't name your drawing, Juno names it "Untitled.juno", and uses the
backup file "Untitled.bak".
Juno automatically deletes the checkpoint file if you successfully save
your work, or whenever you explicitly discard your edits. So if you
see the file around, it means there was a crash while you were using
Juno.
When Juno uses a checkpoint file to recover, it pops up a window
letting you know. If for some reason you prefer the version in the
".juno" file to the checkpoint version, just use the "Open" command to
re-read the ".juno" file, overwriting the state recovered from the
checkpoint.
If you edit a file in a place where you do not have permission to write
a checkpoint file, Juno silently gives up on automatic checkpointing.
If a checkpoint file is found to be corrupted during recovery, recovery
is silently abandoned.
Although Juno does not have a generalized "undo" facility, it does
provide three mechanisms for correcting mistakes.
First, the current command and current module editors record changes to
their contents, and they provide key bindings to undo changes. In the
emacs model, "undo" is bound to "C-_" (control-underscore); in the ivy,
mac, and xterm models, it is bound to "C-z" (control-z). See the
description of the TEXTPORTMODEL environment variable below.
Second, you can abort the application of a tool before you have
supplied all its parameters by selecting another tool. In particular,
if you are using a point tool and make a mistake selecting one of its
arguments (other than the last one), you can start over by selecting
the same tool again from the tool palette.
Finally, you can always correct mistakes you make while editing through
the drawing by directly editing the current command. For example, if
you accidentally apply the Ver tool when you intended to use the Hor
tool, you can change the appropriate occurrence of VER to HOR in the
current command and then click the Run button to effect the change.
Here are the configuration values, their types, and their meanings:
TextFont: Font
The font used for the text in most of the Juno-2 user interface,
including the names of menus, menu items, names of tools in the
tool palette, and error messages.
CodeFont: Font
The font used to display Juno-2 source code. This should be a
fixed-width font.
LabelFont: Font
The font used to display the names of points in the drawing view
when the Labels menu item is set to Letters.
DotSize: REAL
The radius (in pixels) of the dots drawn with labeled points in
the drawing view.
CrossSize: REAL
The "radius" of crosses drawn in the drawing view when the Labels
menu item is set to Crosses.
ChkptIntv: CARDINAL
The interval (in seconds) between automatic checkpoints of the
current file.
RealPrec: CARDINAL
The number of significant digits to which real numbers are
pretty-printed in the program view.
PreviewCmd: TEXT
The command that is run to preview a PostScript file. The command
may include the special substrings "$Display", "$Title", and
"$Filename", which are replaced by the name of the X display on
which Juno was run, the title of the current Juno file, and the
name of the PostScript file to be previewed, respectively.
PrintCmd: TEXT
The command that is run to print a PostScript file piped into it
on standard input. The command may include the special substring
"$Title", which is replaced by the title of the current Juno
file.
Origin: Identifier
The location of the origin in the drawing view. The two possible
origin values are "center" and "southwest". The former causes the
origin to be located at the center of the drawing window and the
center of output pages. The latter causes the origin to be
located in the southwest corner of the drawing window and output
pages.
Orientation: Identifier
The orientation effects the default bounding box and orientation
of the image on PostScript output. The two possible orientations
are portrait and landscape. The former uses a vertically-oriented
8.5" x 11" page, while the latter uses a horizontally-oriented
8.5" x 11" page.
New configuration values can be specified in configuration files. A
Juno configuration file is a sequence of symbolic expressions as
defined in the Modula-3 Sx interface. Each s-exp in the file specifies
a single configuration value. Here is the configuration file syntax.
Strings in single quotes denote literal characters.
File ::= { '(' Cmd ')' }*
Cmd ::= TextCmd | RealCmd | CardCmd | FontCmd
| OrigCmd | OrientCmd
TextCmd ::= TextCmdNames TextVal
TextCmdNames ::= 'PreviewCmd' | 'PrintCmd'
TextVal ::= <Id> | <Text>
RealCmd ::= RealCmdNames <Real>
RealCmdNames ::= 'DotSize'
CardCmd ::= CardCmdNames <Cardinal>
CardCmdNames ::= 'CrossSize' | 'CheckpointIntv' | 'RealPrec'
FontCmd ::= FontCmdNames FontSpec*
FontCmdNames ::= 'CodeFont' | 'TextFont' | 'LabelFont'
FontSpec ::= LFontSpec | XFontSpec
LFontSpec ::= '(' FontName FontWeight FontSize ')'
FontName ::= TextVal
FontWeight ::= 'medium' | 'bold'
FontSize ::= <Cardinal>
XFontSpec ::= <Text>
OrigCmd ::= 'Origin' OrigVal
OrigVal ::= 'center' | 'southwest'
OrientCmd ::= 'Orientation' OrientVal
OrientVal ::= 'portrait' | 'landscape'
A FontCmd includes a list of FontSpec's. Juno will look for the fonts
in turn, and use the first one that is available on your X server.
There are two ways to specify a FontSpec: either as an X font name (see
xlsfonts(1) and xfontsel(1)), or as a triple specifying the name,
weight, and size of the font.
When you select the Configure... menu command from the Juno-2 menu, a
dialog box appears displaying two files. The top, read-only window
displays the contents of a built-in configuration file used to set the
default configuration values. The bottom editable window displays the
contents of the configuration file that was read at start-up (if any).
To change the current configuration values, edit the lower window and
hit the "OK" button.
Juno can be used as the server for a single view of the Zeus animation
system. To run Juno in this mode, you invoke it with the -zeus
command-line option. Before doing so, however, you must be sure the
network object daemon is running on your machine. If you haven't run
one already, you can start a daemon by running the program netobjd(1).
When you run Juno with -zeus, a separate top-level animation window
appears. You can still use Juno for developing your animation code, but
when contacted by Zeus, all drawing is directed to the animation
window.
To implement the view in Juno, you simply define procedures in the
current module for each of your animation's events. Each time Zeus
issues an event, the event arguments are converted to Juno values, and
Juno calls the procedure in the current module with the same name as
the event.
To build a Zeus application that uses Juno to serve one of its views,
just add the lines:
zume(<sessionName>)
junozume(<sessionName>, <viewName>)
to the m3makefile of your Zeus application. The <sessionName> should be
the name of the Zeus session (i.e. the name of the event file), and
<viewName> should be the name you want installed in the Zeus "Views"
menu. You should have at most one "junozume" line in your m3makefile.
To run the animation, you must run the Zeus application on the same
machine as your Juno application and the network object daemon. Once
Zeus is running, you must click on the view named <viewName> in the
Zeus "Views" menu. You will get an error if you select this view and
there is no Juno running as a Zeus server on the same machine.
You can control the animation using the Go, Step, and Abort buttons and
the animation slider just like any other Zeus view. The only difference
is that the animation speed cannot be changed during an event. If you
change the slider during an event, the new slider value won't take
effect until the start of the next event. While a Zeus animation is
running (even if it is paused), the main Juno window is inactive.
When you click the Run or Solve button, Juno compiles the current
module and current command. If a compilation error occurs, Juno
highlights the section of code causing the error and then pops up a
window with an error message. You can click on the error window to
dismiss it.
Most of the compile-time error messages are self-explanatory. If you
get the error message "Extra near constraints", please see Appendix A,
Constraint Solving, of the Juno language definition.
Whenever Juno runs the current command --- for example, when you apply
a tool or click the Run button --- there is the chance that your
program contains a bug that results in a run-time error. To signal a
run-time error, Juno pops up a window with an error message. You can
click on the error window to dismiss it.
The error message window displays the name of the Juno procedure in
which the run-time error occurred, along with the class of the error.
There are four classes of run-time errors:
Executed ABORT
Your program executed the ABORT command, which is defined to
cause a run-time error.
Guard failed
Your program contains a command IF <cmd> FI such that the guard
of the command <cmd> is false. Since Juno brackets the current
command with an implicit IF...FI, this error message most likely
indicates that Juno was unable to solve the current command's
<constraint> for the <variables> from the initial values given
for those <variables>.
Undefined term
Some term in your program was found to be undefined at run-time.
For each function in the Juno language, the language definition
defines the domain of values on which that function is defined.
For example, the "+" and "/" functions are defined only on two
numbers; moreover, "/" is undefined if its second argument (the
denominator) is 0.
Built-in procedure <proc> failed
A run-time error occurred in the built-in PS, Text, Time, or Unit
procedure named <proc>. This error is usually caused by passing
parameters to the procedure that don't meet the procedure's
preconditions. For example, the procedure Text.Cat will fail if
either of its arguments is not a text, and the procedure
PS.SetWidth will fail if its argument is not a positive number.
However, built-in procedures can fail in other ways. For example,
the procedures in the PS module can fail if you are previewing
your drawing and kill the PostScript previewer before the drawing
is finished.
DISPLAY
The X server and screen on which Juno's top-level windows appear.
HOME The user's home directory used to search for the
".juno-config.sx" configuration file.
TEXTPORTMODEL
The editing model for the current command and current module
editors. The editing model determines the key bindings and
selection gestures for these editors. The recognized values are
ivy, emacs, mac, and xterm. If this variable is undefined, the
editing model defaults to emacs.
Other environment variables may be used by the commands specified in
the configuration file to preview and print PostScript output.
Files
Initial contents of current module editor if no other file is
specified on the command-line.
Juno configuration files read if -config is not specified on the
command line.
Bugs
Here are the known bugs in the current version:
* Some configuration values set in the Configuration... dialogue
may not take effect immediately. You may have to reshape the
drawing and program views by dragging the middle vertical bar to
see new values for the CodeFont, LabelFont, DotSize, and
CrossSize configuration variables.
* If you invoke "undo" in either the current module or the current
command editor, it is not noticed by Juno as a change to the
program source. Hence, the Solve button is not activated.
* The compiler does not propagate hints through to pairs. For
example, in the command:
VAR a ~ (1,2), x, y IN
a ~ (x, y) AND x * x = 2 -> SKIP
END
the variable a gets a hint, but the two components of that hint
are not passed on to x and y. This bug is sometimes revealed when
the compiler issues an unexpected "Extra near constraints"
compile-time error message; however, in other cases, the compiler
silently produces code that Juno will fail to solve, usually
resulting in a "Guard Failed" run-time error message.
* If you use the PS.SetBBox tool to set a new bounding box, Juno
fails to change the bounding-box annotation in the drawing view.
To see the correct annotation, just click the Run button, or Drag
or Adjust either of the bounding-box points.
* Juno automatically pretty-prints the current module and command
to fit within the margins. But sometimes it gets the width wrong.
* Juno does nothing to explicitly handle floating point underflows
and overflows. Its response to floating-point exceptions varies
between architectures.
* Juno implicitly recompiles your program in response to certain
user actions. Sometimes, it does not deactivate the Solve button
when it should.
* Applying the PS.Fill tool does not erase the red outline
annotation of the current path, even though the current path is
reset by PS.Fill.
* The path returned by PS.CurrentPath may not correspond exactly to
the current path; its coordinates may be slightly different,
since the path is represented in terms of the integral pixel
coordinates of the points.
* Juno crashes if you try to draw a point too far outside the image
page. This is due to a bug in the X server.
* When printing a Juno drawing on a PostScript device, you may get
a "limitcheck" error if your drawing contains a path that is too
large (i.e., contains too many points). The workaround is to
modify your Juno program to break the path into smaller parts and
to stroke or fill the separate pieces.
Shortcomings
The current version has several shortcomings that we hope to address in
future versions. They are:
* When a run-time error occurs, there is no visual indication as to
where it occurred. Run-time errors should be highlighted in the
program, just like compilation errors.
* There is no convenient way to enter values through the drawing
view other than points, texts, and arguments to set tools.
* There are no provisions for scaled or rotated fonts.
* There is no way to zoom or pan the drawing view.
* There is no convenient "unfold" mechanism.
* You may only name built-in modules in the IMPORT declaration, and
you may only refer to imported modules in qualified identifiers.
However, if your current module does not include an IMPORT
declarations, all of the built-in modules are imported
implicitly.
* It would be nice to be able to adjust a group of points at once.
* It should be possible to set the page orientation on a
per-drawing basis, rather than simply for the entire run of the
Juno application. However, you can change the current orientation
using the Configuration... command under the Juno-2 menu.
If you notice a bug not described in the Bugs or Shortcomings sections,
please send a bug report to heydon@src.dec.com. If the bug you are
reporting caused Juno to crash, please include a pointer to the "core"
file in your message. Sometimes, Juno writes debugging information to
standard error before it crashed; please include such output in your
message. Also, any description of what you were doing to cause the
error would be very much appreciated.
JunoIntf(1), netobjd(1), psview(1), X(1)
Juno-2 Language Definition, by Greg Nelson and Allan Heydon, 14 pgs.
The Juno-2 Constraint-Based Drawing Editor, by Allan Heydon and Greg
Nelson, 20 pgs. This paper gives an introduction to the Juno-2 system
and the algorithm it uses to solve constraints.
Constraint-Based Animations, by Allan Heydon and Greg Nelson, 2 pgs.
This paper describes the basic ideas of using constraints to produce
animations, and of composing simple animations into more complicated
ones using a small set of composition operations.
This man page is also available as a hypertext document under Mosaic at
URL http://src-www.pa.dec.com/SRC/man/AOSF/Juno.1.html.
Allan Heydon (heydon@pa.dec.com)
Greg Nelson (gnelson@pa.dec.com)
Allan Heydon (heydon@pa.dec.com)
Copyright 1995 Digital Equipment Corporation.
Distributed only by permission.
Last modified on Thu Aug 28 17:34:30 PDT 1997 by leifer
modified on Fri Feb 28 10:53:39 PST 1997 by heydon
modified on Wed Aug 16 10:28:43 PST 1995 by gnelson
This file was generated automatically by mtex software; see the mtex
home page at http://www.research.digital.com/SRC/mtex/.
Juno(1)