Juno(1)

Name

Juno - A double-view constraint-based drawing editor

Syntax

Juno [ options ] [ filename ]

Table of Contents

    *   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 constraints 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 segments, 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.

Command-line Options

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, configuration 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 orientation. 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

The current command must be a Juno command. If this command is a projection, 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 <constraint> 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 automatically. For example, when you create a new point in the drawing, a new variable is added to the <variables> section of the current command. The new variable's initial value is the location of its corresponding point.

Editing Through the Drawing View

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, function, 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 single 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 possible 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 particular 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 section below for more information.

Using Point Tools

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 procedure 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 function, then a call to that predicate or function using the point arguments you specified is conjoined onto the end of the <constraint> section 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.

Using Text Tools

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.

Using Template Tools

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.

Using Set Tools

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.

User-Interface Declarations

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.

Using the Special Tools

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 Drawing View

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.

Using the “Run” Button

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.

Working with Long-running Commands

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.

Folding Animations

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.

Pushing and Popping the Current Command

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

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.

Loading/Saving the Current Module

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.

The Built-in Modules

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.

Printing, Previewing, and Producing PostScript

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.

Producing Pixmaps in GIF Format

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.

Crash Recovery

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.

Correcting Mistakes

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.

Setting Configuration Values

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.

Interfacing with Zeus

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.

Compilation Errors

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.

Run-time Errors

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.

Environment Variables

    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.

Reporting Bugs

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.

See Also

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.

Authors of Program

Allan Heydon (heydon@pa.dec.com)
Greg Nelson (gnelson@pa.dec.com)

Author of Documentation

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/.