en fr

Sysquake Pro – Table of Contents

Sysquake – Table of Contents

Sysquake for LaTeX – Table of Contents

SQ Files Reference

This chapter describes the syntax of SQ files, the "programs" run by Sysquake, and the contents of SQ Data files (files with a .sqd suffix), which store the state of a session with an SQ file.

SQ Files

SQ files define the set of interactive plots which can be displayed. Each SQ file corresponds to a specific kind of problem; for instance, one could have SQ files for the design of a digital filter or a PID controller for continuous-time systems, for the study of the effect of initial conditions on a simulation, and so on.

SQ files are text files. You can write them using any text editor or word processor. Make sure that you save them as plain ASCII files, without any style or formatting information; depending on the application, this option is called Text Document, Text Only, ASCII File, or an equivalent expression. Also, do not rely on automatic word wrapping; make sure that all lines end with an explicit end-of-line character. Sysquake accepts carriage returns, line feeds, or both, to accommodate for the text file formats found on different operating systems.

SQ files contain different kinds of elements:

Declaration of variables
Variables are used as parameters for the figures, menu item actions, etc. Manipulating a figure changes some of the variables, and all the figures currently displayed are updated to reflect the changes. These variables, called Sysquake variables, must not be confounded with LME variables (variables used without declaration in LME functions).
Definition of constants
Integer literal values can be given a name to make the code clearer. These definitions are visible in the declaration part of SQ files as well as in function definitions.
Declaration of handlers
Handlers are expressions executed to perform different tasks managed by Sysquake, such as initialization, figure manipulation, menu selection, etc. They have the same syntax as LME assignments, or expressions if no result is to be used. As input and output, they use Sysquake variables as well as values managed directly by Sysquake, such as the position of the mouse. Variables in the left-hand side of assignments cannot use indexing or structure field access. Values managed by Sysquake are identified with a name beginning with an underscore; they can be used either directly in the handler declaration, or indirectly in a function called in a handler declaration.
Function definitions
Handlers are implemented by functions written in LME, an interpreted language well suited for numeric computation.
Help
A textual description can be provided in SQ files. Sysquake displays it upon user request.

Syntax

SQ files contain declarations, blocks of text, and comments. Declarations are always placed at the beginning of a line; they start with a keyword, and are usually followed by other elements. Here is the list of keywords:

beginmenu
beginsubmenu
data
define
draw
dragin
dragout
embeddedfile
endmenu
endsubmenu
export
extension
fighandler
figure
function
functions
help
idle
import
init
input
keydown
make
menu
mousedown
mousedoubleclick
mousedrag
mousedragcont
mouseout
mouseover
mousescroll
mouseup
output
publichandler
resize
separator
terminate
title
use
userinterface
variable
variables
version
watch
 

Remark: all these keywords are supported on all versions of Sysquake to assure the compatibility of SQ files. However, import, export and extension declarations have an effect only on the full version of Sysquake.

Declarations must be either contained on a single line or split into several lines with the continuation characters ... at the end of the first line(s):

variable a, b, ...
         c, d, e

Many keywords are followed by handler declarations. These handlers are implemented in LME code in a functions block and may accept input arguments and output arguments. Arguments may be variables declared in the SQ file, special arguments beginning with an underscore, or (for the input arguments) integer numbers or named constants. In some case, handler declarations may be reduced to a simple assignment such as y=x or num=3. Expressions are not allowed.

Comments are either enclosed between /* and */ or span from // or % to the next end of line. They cannot be nested.

Declaration of Variables

Variables defined at the level of the SQ file play a very important role in Sysquake. They are global; all handlers can use them as input and/or output arguments. They are preserved between handler executions. They contain the whole state of Sysquake; together with the SQ file itself, they permit to restore what appears in the Figure window, and are used in the Save mechanism. Finally, they are the base of the Undo system, which enables the user to cancel the last operations (such as manipulating a figure with the mouse, changing a subplot or entering numeric values in a dialog box) and redo them.

Variables are declared with the variable (or variables) keyword, followed by one or several variable names separated by commas or spaces. They can contain any data type supported by LME, such as numbers, arrays, strings, structures, etc. Variables are always defined; variables whose value has not been set explicitly contain the empty array []. Variable names are made of letters, digits and underscores; they begin with a letter, and case is significant, like everywhere else in Sysquake. Names beginning with an underscore are reserved for special purposes and should not be used for variables.

Five variables are managed by Sysquake and cannot be used in handlers: _plots, a string which contains the name of the subplots (see function subplots); _plotprops, an array which contains the properties and scaling of each subplot (see function subplotprops); _plotpos, an array which contains the position of subplots when Free Position is enabled (see function subplotpos); _plotsync, an array which defines which and how subplot scales are synchronized (see function subplotsync); and _plotparam, a list whose elements are arbitrary data specific to each subplot (see function subplotparam). They are revealed when the state of Sysquake is saved to SQ Data files.

Example

variable x
variables num den

Variables can be initialized in the init handler(s) (see below), or directly in the variable declaration; in that case, only one variable can be declared and initialized for each declaration statement, and the expression on the right of the equal character must not depend on other variables.

Example

variable x = 2
variable vec = 1:10

If the expression on the right of the equal character depends on other variables, the variable on the left is declared, and the assignment is treated as a make handler (see below), i.e. the assignment is performed everytime the variable is used and its dependencies have changed.

Variables can be declared nondumpable to prevent Sysquake from saving and restoring them, be it with the Undo/Redo mechanism or with Save and Open. Nondumpable variables can be used and modified like any other variable; however, modifying them with any handler will prevent Undo from restoring their previous state, and Save (or Dump Data) will skip their value (the saving mechanism is detailed later in this chapter). Variables which should be declared as nondumpable include file descriptors for files and serial port connections: a file descriptor is only valid if the corresponding file or device has been opened with fopen or similar functions for devices.

Nondumpable variables are declared with the keyword _nondumpable following immediately variable. No comma may precede or follow _nondumpable. Dumpable and nondumpable variables may not be mixed in the same declaration.

Example

variables _nondumpable fd, connection

Declaring variables explicitly incites to plan how they will be used as the glue between the different handlers. It makes easier the documentation; each variable can be commented, and their enumeration, if self-explanatory names are chosen, is itself an important help for future maintenance. But in case where small scripts are preferred (maybe as a compact version for on-line distribution), implicit declarations are also possible. Implicit declarations are enabled as follows:

variable _implicit

When implicit declarations are enabled, all the variables appearing in handler declarations are managed by Sysquake exactly as if they had been declared explicitly in variable statements. Implicit variables cannot have the _nondumpable attribute; however, you can declare only the nondumpable variables and have a variable _implicit declaration for all other variables.

Definition of constants

Some numbers are used as identifiers at different places. For instance graphical objects which can be manipulated with the mouse are tagged with an identifier when they are displayed, and this identifier is used to recognize them when the user clicks them. Numeric ID can be replaced with more meaningful names with constant definitions. Constant definitions begin with the keyword define, followed by the identifier, the equal character, and the integer value or the keyword _auto. Constants defined with _auto are numbered consecutively from 1. In the example below, kGainID is 1, kDelayID is 2, etc.

Example

define kGainID = _auto
define kDelayID = _auto
define kMassID = _auto
define kYMaxID = 1000

The definition is valid not only in the declaration part of SQ files everywhere an integer number could appear, but also in functions defined in function blocks. If the definition is placed inside a function block, it cannot be referenced in handler declarations.

Init and Terminate Handlers

The purpose of init handlers is to provide default values for the variables and the plot options. Variables are initialized with the values returned by the init handler(s); other variables (those not enumerated in the left-hand part of init handler declarations) are set to the empty array []. Initial plots are set up with commands subplots, subplotprops, subplotpos, scalesync or subplotsync, and subplotparam. By default, the first figure is displayed. The same functions can be used without any argument to retrieve the corresponding values; this is especially useful to store these settings in a data file.

Example

function [A,B,R,S] = init
  // default values for A, B, R and S
  A = [1,1];
  B = 1;
  R = 1;
  S = 5;

  // default plots
  subplots('roots\tstep');
    // kind of plots, separated with tabs and line feeds
    // (one row of two subplots)

  props = [0,-2,0,-1,1         // lin. scale, zoom on [-2,0,-1,1]
           0,nan,nan,nan,nan]; // default lin. scale
  subplotprops(props);

When variables are initialized separately, i.e. when the init handler does not return multiple output arguments, and the initialization expression does not depend on another variable, initialization can be done in the variable declaration statement. The following declaration

variable x = 2

is equivalent to

variable x
init x = 2

Should resources be allocated by the init handler, a terminate handler can be defined to release them. This is necessary only if commands with side effects are used, for instance if a file is opened by the init handler. The terminate handler is declared like other handlers. Output variables are useless, because the variables are discarded immediately after its execution.

terminate termFn(var)

Example

Here is an example of init and terminate handlers which open and close a file, respectively. Other handlers can read from or write to the file. In this example, a custom input handler should be written to avoid resetting the value of the file descriptor fd (see below).

variable fd

init fd = init
terminate terminate(fd)

functions
{@
function fd = init
    fd = fopen('data.txt', 'rt');

function terminate(fd)
    fclose(fd);
@}

Multiple init and terminate handlers can be declared; they are all executed in the same order as they are declared.

Resize handler

The resize handler is a function called when the dimensions of the area where the figures are displayed are changed. This occurs typically when the user resizes the window. The resize handler is declared with the keyword resize. Two special input arguments can be used to retrieve the new size of the subplots area:

NameDescription
_height height of the subplots area in pixels
_width width of the subplots area in pixels

The height and width are usually given in pixels for the screen, and in points (1/72 inch) for high-resolution devices such as printers.

The purpose of the resize handler is to change the subplot layout, for instance to reduce their number when the display area is too small. The resize handler is not called at startup; arguments _height and _width can also be passed to the init handler.

Example

In the fragment of SQ file below, the subplot layout is set in the function setSubplots, which is called as an init handler at startup and as a resize handler when the window dimensions are changed. Depending on the width of the window, one or two figures are displayed. A separate init handler is declared for variable initialization.

variable a, b, c
init (a, b, c) = initVar
init setSubplots(_width)
resize setSubplots(_width)
...

functions
{@
function (a, b, c) = initVar
  ...
function setSubplots(width)
  if width > 300
    subplots('Fig. 1\tFig. 2');
  else
    subplots('Fig. 1');
  end
...
@}

Figure Declaration

Each figure is declared by a figure declaration, introduced by the figure keyword:

figure "Figure Name"

The string which follows the figure keyword is the figure name, which can contain any character and space. It is displayed as a title above the figure and in the Plots menu, and is used by the subplots command as an identifier. The figure declaration is followed by the draw, mousedown, mousedoubleclick, mousedrag, mousedragcont, mouseup, mouseover, mouseout, mousescroll, dragin, and dragout handlers corresponding to the figure. Only the draw handler is required.

The Plots menu follows the order of the figure declarations. Separators (horizontal lines in the menu) can be inserted to make the menu easier to read, with the separator keyword.

Related figures can be grouped in submenus. Figure entries are enclosed between beginsubmenu "name" and endsubmenu lines, where name is the name of the submenu.

Example

figure "Input Signal"
  draw drawInputSignal(u);
  mousedrag u = dragInputSignal(u, _id, _y1);
  mouseover _cursor = overInputSignal(_id)

figure "Output Signal"
  draw drawOutputSignal(y);

separator

figure "Model"
  draw drawModel(u, y);

separator

beginsubmenu "Response"

  figure "Impulse"
    draw drawImpulse(u, y)
  
  figure "Step"
    draw drawStep(u, y)

endsubmenu

Draw Handler

Each figure has one draw handler, declared with the draw keyword:

draw drawFn(v1, v2, ...)

The handler draws the figure with graphical commands such as plot, circle, or step. The scale command may be used to set the default scale and the scale options.

The draw handler typically has input arguments; but it never has any output argument. It also accepts the special input argument _param (see below).

Mousedown, Mousedoubleclick, Mousedrag, Mousedragcont, Mouseup, Mouseover, and Mouseout, and Mousescroll Handlers

The mousedown, mousedoubleclick, mousedrag, mouseup, mouseover, mouseout handlers are called when the mouse is over the figure they are defined for and the mouse button is pressed, double-clicked, held down, released, left unpressed, or move outside respectively. The mousedragcont handler is an alternative to the mousedrag handler (see below). The mousescroll handler is called when the mouse if over the figure and the scroll wheel or scroll ball is moved. The dragin and dragout handlers are used for drag operations between different figures. The table below summaries their differences. For example, the mousedrag handler accepts variables (declared with the variable keyword) as input and output arguments; it can set the special variable _msg with an output argument, and its role is to modify variables during a mouse drag.

HandlerVar._msg_cursorRole
mousedownin/out--Prepares a drag
mousedoubleclickin/out--2nd click of a dble-click
mousedragin/outout-Performs a drag
mousedragcontin/outout-Performs a drag
mouseupin/out--Cleans up after a drag
mouseoverin/outoutoutGives visual feedback
mouseoutin/out--Cleans up visual fdback
mousescrollin/outout-Performs a change

The purpose of the mouseover handler is to give to the user visual feedback about what is below the cursor, with a message or the shape of the cursor. It is also possible to change the variable, and though them all the displayed graphics, when the mouse is moved over a figure. This should be used only to give some additional hint about what is below the cursor (such as highlighting a matching element in another graphics), not as a substitute of mousedrag, because the user has no way to select what he wants to manipulate. The mouseout handler should be used to restore the state of the variables.

The purpose of the mousedown, mousedoubleclick, mousedrag, mousedragcont, and mouseup handlers is to handle interactions. They receive as input arguments the position of the mouse and the value of variables, and return as output arguments new values for the variables. Unless an error occurs, the mousedown, mousedrag, mouseup, and draw handlers are called with the following arguments. The placeholder S0 represents the set of variables before the mouse down, and S1 the set after the mouse up.

S0 = mousedown(S0)
S0 = draw(S0)
S1 = S0
while the mouse button is down
  S1 = mousedrag(S0)
  S1 = draw(S1)
end
S1 = mouseup(S0)
S1 = draw(S1)

The Undo command discards S1 and reverts to S0. Hence the changes caused by mousedown should be limited to computing auxiliary values used for the drag operation, but invisible to the user. If an error occurs, the sequence is aborted, and S1 is discarded.

The sequence above can be reduced to much simpler forms. For dragging an element, it is often sufficient to define mousedrag and draw:

while the mouse button is down
  S1 = mousedrag(S0)
  S1 = draw(S1)
end

To change the controller on a simple mouse click, only the mouseup handler is used (as explained above, the mousedown function does not change S1).

S1 = mouseup(S0)
S1 = draw(S1)

The mousedrag handler is always executed immediately after the mousedown handler if there is one, even if the mouse is not moved. To display some information without changing anything when you drag the mouse and remove any trace afterwards, you can define a mousedrag handler which sets variables used by the draw handlers, then discard S1 with a mouseup handler which just contains the cancel command.

The mousedrag handler uses as input arguments the values the variables had before the drag. After the drag, the variables will be affected only by the position of the mouse at the beginning and at the end of the drag operation; the trajectory of the mouse is lost. This behavior is often desirable. In the infrequent cases where it is not, the mousedrag handler should be replaced with a mousedragcont handler. Sysquake calls the handlers in the following sequence:

S0 = mousedown(S0)
S0 = draw(S0)
S1 = S0
while the mouse button is down
  S1 = mousedragcont(S1)
  S1 = draw(S1)
end
S1 = mouseup(S0)
S1 = draw(S1)

The only difference with the mousedrag handler is that mousedragcont handlers use the new values of the variables as input arguments and modify them continuously. They can record the whole trajectory of the mouse (or any information derived from the trajectory). For example, a mousedragcont handler could be used to draw in a pixmap.

The mousedoubleclick handler is called when the mouse button is pressed down for the second time shortly after the first one. The mousedown, mousedrag, mouseup and draw handlers (if they exist) have been called for the first click.

The purpose of the mousescroll handler is to to change some quantity related to a figure or an object. Since all mouses do not have wheels, tracking balls, or other scrolling device, the mousescroll handler should be a shortcut to some other way of performing the same action, for instance with a dialog box or a slider. This is espacially true for horizontal scroll which is not supported by most wheels. Note also that some wheels have a coarse resolution.

Predefined variables

In addition to the variables defined with the variable keyword, you can use the following predefined variables as input argument for the mousedown, mousedoubleclick, mousedrag, mouseup, and mouseover handlers.

Name Purpose
_z initial position of the mouse as a complex number
_x initial horizontal position of the mouse
_y initial vertical position of the mouse
_rho initial distance between the position of the mouse and the origin
_theta initial angle of the vector from the origin to the position of the mouse
_z0 initial position of the clicked element as a complex number
_x0 initial horizontal position of the clicked element
_y0 initial vertical position of the clicked element
_p0 initial position of the clicked element as a 2D or 3D vector
_rho0 initial distance between the position of the clicked element and the origin
_theta0 initial angle of the vector from the origin to the position of the clicked element
_z1 current position of the mouse as a complex number
_x1 current horizontal position of the mouse
_y1 current vertical position of the mouse
_p1 current position of the mouse as a 2D or 3D vector
_rho1 current distance between the position of the mouse and the origin
_theta1 current angle of the vector from the origin to the position of the mouse
_str1 current string parameter
_dx horizontal displacement (_x1-_x) or horizontal scrolling
_dy vertical displacement (_y1-_y) or vertical scrolling
_dz displacement (_z1-_z) or scrolling as a complex number
_kx factor the horizontal position is multiplied by (_x1/_x)
_ky factor the vertical position is multiplied by (_y1/_y)
_kz complex factor the position is multiplied by in the complex plane (_z1/_z)
_q additional data specific to the plot
_m true if the modifier key (Shift key) is held down
_id ID of the manipulated object
_nb number of the manipulated trace (1-based)
_ix index of the manipulated point (1-based)
_param subplot parameter

The value of _z0 is constrained to existing elements of the plot, contrary to _z which represents the actual position of the mouse click. The value of _z1 is not constrained. If you need the original position of the manipulated object, you should usually use _z0 (or _x0 or _y0) and replace it with _z1. The value of _z is used when the amplitude of the move is considered, not the initial and final positions, or when no object is selected.

The value of _id is the value you define in plot commands for elements you want to manipulate. You can use it to recognize different graphical objects in the same figure. The value of _nb defines which line is manipulated among those plotted by the same command (most graphical commands can draw multiple lines or multiple responses). The value of _ix, an integer starting from 1, is always defined when the user selected an element of the figure; it is useful mainly for traces where you define explicitly each point, e.g. plot and line. Note that you need not use IDs; all clicks generate calls to the mouse handler(s), and _z, _z1, _x, _x1, _y, and _y1 are always defined.

For each subplot, Sysquake maintains a piece of data which can be used freely for any purpose. This data is passed to and from all figure-related handlers with _param. It is initialized to the empty array []. It is useful in cases where the same figure is displayed in different subplots; _param may contain for instance initial conditions for a simulation. It may also be used as input or output argument of menu, import and export handlers and in their _enable and _checkmark expression; in these cases, the handlers are enabled when a single subplot is selected.

As output argument of the mousedrag and mouseover handlers, you can use the following special variables:

Name Purpose
_msg string displayed in the status bar at the bottom of the window
_param new value of the subplot parameter

The variable _msg is typically set to describe what is below the cursor, with possibly some numeric values using sprintf. If it contains a linefeed ('\n') or carriage return ('\r') character, it is truncated.

As output argument of the mouseover handler, you can also use the following special variable:

Name Purpose
_cursor true to display the cursor as a finger in manipulate mode

The shape of the cursor gives a hint to the user whether he can manipulate the object below the cursor. This can makes the use of SQ files much easier. By default in manipulate mode, the finger cursor is displayed in figures where mousedown, mousedrag and/or mouseup handlers are defined; otherwise, the cursor is the standard arrow. Sliders, buttons, and other controls (see command slider) are a special case; the finger is displayed only when the cursor is over a slider. In case you define mouse handlers, though, you often want to specify explicitly whether any manipulation is possible.

Example

Here are handlers for displaying the roots of a polynomial A that you can manipulate.

variable A = poly([-1, -2-2j, -2+2j])

figure "Roots"
  draw drawRoots(A)
  mousedrag A = dragRoots(A, _z0, _z1)
  mouseover _cursor = overRoots(_id)

functions
{@
function drawRoots(A)
  // plot the roots of polynomial A
  plotroots(A, 'x', 1);
  scale lock;
  
function A = dragRoots(A, z0, z1)
  // if the click is too far away from a root of A, z0 is empty
  if isempty(z0)
    cancel;                 // discard the dragging operation
  end
  A = movezero(A, z0, z1);  // move the root
  
function cursor = overRoots(id)
  // displays a finger if the cursor is over a root,
  // and a plain cursor otherwise
  cursor = ~isempty(id);
@}

One thing to note about cursors, if your mouseover handler declaration specifies _cursor as the (or one of the) output(s), and your mouseover handler is canceled by cancel, the cursor is set to the plain arrow. Hence you can have code like

if isempty(id)
  cancel;
end

early in your mouseover handler.

Here is an example which shows how the mousedragcont handler can be used to accumulate the position of the mouse during a drag.

variable x, y  // position of the mouse

figure "Plot"
  draw draw(x, y)
  mousedragcont (x, y) = drag(x, y, _x1, _y1)

functions
{@

function draw(x, y)
  // display the trace of the mouse
  scale('equal', [0,10,0,10]);
  plot(x, y);

function (x, y) = drag(x, y, _x1, _y1)
  // add the current position of the mouse to x and y
  x(end + 1) = _x1;
  y(end + 1) = _y1;
@}

Handlers for a specific ID

Instead of a single handler which is called when required whatever there is under the mouse, you can restrict the handler to a specific ID value. The handler is called only if the mouse is over an object with that ID. You can have multiple handlers of the same type with different ID. This can simplify the code: the handler does not have to check that the ID is not empty and has the correct value, and multiple handlers can have a smaller number of arguments.

The ID is placed directly after the handler keyword, either as an integer or a constant name defined with define. The example below is a complete SQ file where you can move two points, the first one horizontally and the second one vertically. Note that the mousedrag handlers are so simple they do not need a function. Since there are mouseover handlers with specific ID, but no generic one, the cursor is displayed as a finger only over one of the points.

variable p1x = 0.3
variable p2y = 0.6

define kP1Id = 1
define kP2Id = 2

figure "Points"
  draw drawPoints(p1x, p2y)
  mousedrag kP1Id p1x = _x1
  mouseover kP1Id _msg = overP1
  mousedrag kP2Id p2y = _y1
  mouseover kP2Id _msg = overP2

functions
{@
function drawPoints(p1x, p2y)
  scale([0, 1, 0, 1]);
  plot(p1x, 0.5, 'x', kP1Id);
  plot(0.5, p2y, 'o', kP2Id);

function msg = overP1
  msg = 'Point 1';

function msg = overP2
  msg = 'Point 2';
@}

Fighandler Handler

Separate handlers for the different events which can occur result typically in small functions. While the implementation of these functions can be very simple, code reuse is complicated: only the function definitions can be stored in separate libraries, while the multiple handler declarations (often at least a draw handler, a mousedrag handler and a mouseover handler) must be inserted in the SQ file.

Fighandler handlers replace all the handlers related to figures, i.e. draw, mousedown, mousedoubleclick, mousedrag, mousedragcont, mouseup, mouseover, mouseout, mousescroll, dragin, and dragout. In the handler, the action to perform is given by _event, which is typically used in a switch construct. Upon events to be ignored, cancel(false) should be executed.

Example

Here is the example for figure "Roots" given above, rewritten with a single fighandler function instead of separate draw, drag and over handlers.

variable A = poly([-1, -2-2j, -2+2j])

figure "Roots"
  fighandler A = figRoots(A)

functions
{@
function A = figRoots(A)
  switch _event
    case 'draw'
      plotroots(A, 'x', 1);
      scale lock;
    case 'drag'
      if isempty(_z0)
        cancel;
      end
      A = movezero(A, _z0, _z1);
    case 'over'
      _cursor(~isempty(_id));
    otherwise
      cancel(false);
  end
@}

Menu Handler

The interactive manipulation of graphical elements is not suited for all the modifications of the variables. To change the structure of a controller or to specify numeric values, a command triggered by a menu entry, possibly with the help of a dialog box, is more convenient. This is the purpose of menu handlers, which are installed in the Settings menu. Menu handlers are declared as follows:

menu "Title" (out1, out2, ...) = function(in1, in2, ...)

The string is the menu entry title. The function typically gives new values to one or more variables. If numeric values must be entered or modified by the user, or if a confirmation is required, the dialog command should be used. To cancel the action, the cancel command must be used to prevent a new set of variables from being created in the Undo buffer.

Like figures, menu entries are listed in the Settings menu in the same order as their declaration in the SQ file. Separators can be added with the separator keyword, and entries can be grouped in submenus with beginsubmenu and endsubmenu keywords. In addition, instead of the default Settings menu, menu entries can be grouped in different menus with the beginmenu and endmenu keywords. On versions of Sysquake which do not support multiple menus, these keywords are also accepted for compatibility; separators are inserted automatically.

The appearance of the menu entries can be modified in two ways: they can be disabled (they are written in gray and cannot be selected) with the _enable keyword, and they can be decorated with a check mark with the _checkmark keyword. Both keywords must appear between the menu handler title and the handler function declaration. They use a single LME boolean expression (typically based on the variables) as argument.

Examples

In the following example, the variable color has the value 0 for black, 1 for blue and 2 for red.

variable color, polygon, sides

init color = 0
init polygon = 0
init sides = 3

beginsubmenu "Color"
  menu "Black" _checkmark(color==0) color=0
  menu "Blue" _checkmark(color==1) color=1
  menu "Red" _checkmark(color==2) color=2
endsubmenu
separator
menu "Polygon"
     _checkmark(polygon) polygon=toggle(polygon)
menu "Number of Sides..."
     _enable(polygon) sides=setNumberOfSides(sides)

functions
{@
function b = toggle(b)
  b = ~b;

function sides = setNumberOfSides(sides)
  (ok, sides) = dialog('Number of sides:', sides);
  if ~ok
    cancel;
  end
@}

In the fragment below, two menus are declared:

beginmenu "Color"
  menu "Black" _checkmark(color==0) color=0
  menu "Blue" _checkmark(color==1) color=1
  menu "Red" _checkmark(color==2) color=2
endmenu
beginmenu "Parameters"
  menu "Polygon"
     _checkmark(polygon) polygon=toggle(polygon)
  menu "Number of Sides..."
     _enable(polygon) sides=setNumberOfSides(sides)
endmenu

Sysquake will display two menus whose titles are "Color" and "Parameters".

Keydown Handler

To react to a key pressed down, multiple specific keydown handlers and a single default keydown handler can be installed. Specific keydown handlers are declared as follows:

keydown "k" (out1, out2, ...) = function(in1, in2, ...)

The string "k" contains the key which triggers the handler when pressed. Most keys are denoted by the corresponding character; arrow keys are denoted by "up", down, left, and right.

The default keydown handler is declared as follows:

keydown (out1, out2, ...) = function(in1, in2, ...)

It is triggered if a key without a specific keydown handler is pressed. In both kinds of keydown handlers, the function typically gives new values to one or more variables. In addition to the variables defined with the variable keyword, you can use the following predefined variable as input argument:

Name Purpose
_key key pressed as a string

Example

In the following example, the variable n is incremented or decremented when the user type "+" or "-", respectively. When another key is pressed, cancel is executed, so that no new undo frame is created.

variable n

init n = 1
keydown n = keydownHandler(n, _key)

functions
{@
function n = keydownHandler(n, key)
  switch key
    case '-'
      n = n - 1
    case '+'
      n = n + 1
    otherwise
      cancel;
  end
@}

Make Handler

It is often useful to have variables which hold the result of a computation based on other variables. If several figures depend on it, this avoids the need to calculate it in each draw handler and reduce the computation time. The computation may be performed in the handlers which change the independent variables. However, this forces to add arguments; handlers become more difficult to write, especially when dependencies are complicated. Make handlers describe the way to calculate variables not as the direct effect of some user action, but when their output arguments are required by another handler. The name make is borrowed from the programming utility which builds a complicated project based on a set of rules and dependencies. Make handlers do the same for variables. Their declaration is simply

make (output_variables) = makeHandler(input_variables)

Suppose that a variable x is changed, and that the draw handler of a figure uses variable y as input argument. If the following make handler is declared,

make y = f(x)

Sysquake calls the function f to compute y based on x. More complex dependencies may be defined using several make handlers. There must not be circular dependencies; no variable may depend on itself through one or more make handlers.

When a make handler gives the value of a single variable, it can be specified in the variable declaration statement. The following declaration

variable x, y
variable z = x + y

is equivalent to

variable x, y, z
make z = x + y

Examples

The examples below represent three different ways to implement the same behavior. A variable x may be modified either in a menu handler or by interactive manipulation of a figure. Two figures uses variable y, which is a function of x.

The first implementation does not store y in a variable declared to Sysquake. It is computed in each draw handler.

variable x
init x = init
menu "Change x" x = changeX(x)
figure "Figure 1"
  draw drawFig1(x)
  mousedrag x = dragFig1(_x1)
figure "Figure 2"
  draw drawFig2(x)
functions
{@
function x = init
  x = 3;
function x = changeX(x)
  // (dialog box to let the user edit x)
function drawFig1(x)
  y = f(x);
  // (plot based on x and y)
function x = dragFig1(x1)
  x = x1;
function drawFig2(x)
  y = f(x);
  // (other plot based on x and y)
function y = f(x)
  // computation of y
@}

The second implementation declares y, which is computed in all handlers which change the value of x. When both figures are displayed, y is computed only once when the menu or mousedrag handler is invoked.

variable x, y
init (x, y) = init
menu "Change x" (x, y) = changeX(x)
figure "Figure 1"
  draw drawFig1(x, y)
  mousedrag (x, y) = dragFig1(_x1)
figure "Figure 2"
  draw drawFig2(x, y)
functions
{@
function (x, y) = init
  x = 3;
  y = f(x);
function (x, y) = changeX(x)
  // (dialog box to let the user edit x)
  y = f(x);
function drawFig1(x, y)
  // (plot based on x and y)
function (x, y) = dragFig1(x1)
  x = x1;
  y = f(x);
function drawFig2(x, y)
  // (other plot based on x and y)
function y = f(x)
  // computation of y
@}

The third implementation also declares y, which is computed by a make handler when it is needed by another handler. Note how each handler is as simple as it can be. If none of the two figures is displayed, y is not computed at all.

variable x, y
init x = init
make y = f(x)
menu "Change x" x = changeX(x)
figure "Figure 1"
  draw drawFig1(x, y)
  mousedrag x = dragFig1(_x1)
figure "Figure 2"
  draw drawFig2(x, y)
functions
{@
function x = init
  x = 3;
function x = changeX(x)
  // (dialog box to let the user edit x)
function drawFig1(x, y)
  // (plot based on x and y)
function x = dragFig1(x1)
  x = x1;
function drawFig2(x, y)
  // (other plot based on x and y)
function y = f(x)
  // computation of y
@}

Function Definitions

Functions declared by the different handlers must be built-in, defined in separate libraries, or defined in one or several function blocks.

A library (.lml file) must be referenced with the use keyword:

use library

The library name does not include the file suffix .lml. Libraries are searched in the same folders or directories as SQ files.

Functions defined directly in the SQ files are placed in a function block, with the following syntax:

function
{@
...
@}

The keyword functions is a synonym of function. The functions can be defined in any order and in any number of blocks. In addition to functions declared as handlers, other functions can be defined to extend the set of built-in commands.

Function blocks can also include use statements. Whether to place use statements outside or inside function blocks is a matter of style. SQ-level use statements should be preferred for libraries which define functions called directly as handlers.

Embedded files

In some cases, especially when a large amount of constant data is required in an SQ file, it may be convenient to store these data in the SQ file itself and to use the standard input functions of LME, such as fread and fscanf, to retrieve them. This avoids the need of separate files. Blocks of texts, introduced by keyword embeddedfile, provide such a facility:

embeddedfile "name"
{@
Embedded file contents...
@}

The contents of the block may be as large as required. They can be either plain text, or binary data encoded with base64. The name is used to identify the embedded file; it corresponds to the argument of function efopen. The number of embedded files in an SQ file is not limited.

Title, Version, and Help

SQ files may include a title, version information, and explanations about their purpose and how they can be used. The title is specified by a string:

title "..."

It is used instead of the file name in some windows and menus titles.

The version and help are provided in blocks of text:

version
{@
Text...
@}

help
{@
Text...
@}

In the block of text, paragraphs are separated by one or more empty lines. Initial and trailing empty lines and spaces are ignored. For cases where preformatted text is preferred, such as for program code or equations, the HTML tags <pre>/</pre> are used. Here is an example:

help
{@
Here is an identity matrix:

<pre>
    [ 1 0 0 ]
I = [ 0 1 0 ]
    [ 0 0 1 ]
</pre>
@}

Upon user request, Sysquake displays the version or the help of the current SQ file.

The purpose of the version text is to give any version number, release date, and copyright information relevant to the SQ file.

User interface

The standard user interface of Sysquake has menus to customize the layout of figures and their options. Some of them can be disabled once the layout has been carefully tuned. This is done with the userinterface keyword, followed by comma-separated options:

userinterface option1, options, ...

Here is the list of supported options:

Name Purpose
appmenus (default) Standard menus
noappmenus No standard menus
figoptions (default) Submenu "Figure>Options" for margin, title, etc.
nofigoptions No submenu "Figure>Options"
plotchoice (default) Menus "Plots" and "Layout"
noplotchoice No menus "Plots" and "Layout"
resize (default) The figure window can be resized
noresize The figure window has a fixed size
selectall (default) Menu entry "Edit>Select All"
noselectall No menu entry "Edit>Select All"
toolbar (default) Figure toolbar
notoolbar No figure toolbar

Depending on the version of Sysquake, the menus or menu entries are disabled or completely removed. Option noplotchoice also disables the dragging of subplots. Option noappmenus removes most menus and menu entries.

To have finer control on exactly which plot options should be available, the Figure menu should be removed with nofigoptions and the appropriate options added back in menus with sqguicmd. The code below shows a reduced menu with logarithmic scale for x and y axis, and labels and legends.

userinterface nofigoptions

beginmenu "Options"
  menu "Log x"
    _enable(sqguicmd('scale/log-x','e'))
    _checkmark(sqguicmd('scale/log-x','c'))
    sqguicmd('scale/log-x')
  menu "Log y"
    _enable(sqguicmd('scale/log-y','e'))
    _checkmark(sqguicmd('scale/log-y','c'))
    sqguicmd('scale/log-y')
  separator
  menu "Label"
    _enable(sqguicmd('figure/label','e'))
    _checkmark(sqguicmd('figure/label','c'))
    sqguicmd('figure/label')
  menu "Legend"
    _enable(sqguicmd('figure/legend','e'))
    _checkmark(sqguicmd('figure/legend','c'))
    sqguicmd('figure/legend')
endmenu

SQ Data Files and Input/Output Handlers

SQ Data files (or SQD files) are composed of a succession of LME statements which define variables. The contents of these variables are used by an input function which translates them to the variables used by Sysquake itself and which restores the subplots and their settings. This filtering step serves two purposes:

To avoid the hassle to write input and output handlers when these advanced features are not needed, Sysquake has a default behavior if the handlers are not declared in the SQ file. If the output function is missing, all the variables and the settings are written to the file. If the input function is missing, the variables declared in the SQ file are set to the values defined in the SQD file, or to the empty array [] if they are not found.

To permit the user to simply open the SQ data file without specifying the SQ file which can make use of it, the first line should form a valid LME comment with the name of the associated SQ file:

%SQ sqfile.sq
...

When the user opens a file, the first line is read. If it corresponds to a data file, the associated SQ file is read and its init function processed. Finally, the data file is executed and the contents of its variables converted by the input function. If the file opened by the user is a SQ file, it is read and its init function executed.

A typical data file could be

%SQ greatDesign.sq

A = [1,2];
B = 2;
kp = 20;
_plots = 'greatView\tstep';
_plotprops = [0,-1,1,-1,1;
0,10,50,0,0];

Variables A, B, and kp correspond directly to variables defined in the SQ file. Variable _plots is the list of the subplots which were displayed when the file was saved; it corresponds to the input or output argument of the command subplots. Variable _plotprops is the properties of the subplots (options like logarithmic scaling and grids, and zoom); it corresponds to the input or output argument of the command subplotprops. The names _plots and _plotprops are those used by the default input and output handlers; it is better to use them also if you write your own handlers.

Input and Output Handlers

To generate and read back the data file above, the following handlers can be declared:

output outputHandler(_fd, v1, v2, ...)
input (v1, v2, ...) = inputHandler(_fd)

The output handler must write to file descriptor _fd the contents of the variables. You need not save all the variables; for example, if pol is a polynomial and you have defined a variable r to store its roots, saving pol is enough; you can restore r in the input handler with r=roots(pol). The variable _fd represents the file descriptor of the output file:

Name Purpose
_fd file descriptor of the output or input file

Like all special arguments, _fd can also be used directly in the function definitions, without being passed from the handler declaration.

You can use it with functions such as fprintf and dumpvar. You can write the data using any format. However, it is better to follow the format of standard SQD files, as described above, with perhaps calls to the built-in functions of LME. The first line, which contains the name of the SQ file, is required to permit Sysquake to find the appropriate SQ file.

The input handler reads the SQD file using the file descriptor _fd, and produces values stored in Sysquake variables. The input handler is always called after the init handler; variables which are not output arguments of the input handler keep the value set by the init handler.

If the SQD file contains variable assignments, the easiest way to parse it is to read the whole file with fread, and to interpret the string with sandbox.

The following example shows how to write input and output handlers which save and restore three variables, check the validity of the variables in the SQD file, and save and restore the subplots.

output myOutputHandler(A,B,kp)
input (A,B,kp) = myInputHandler()

function
{@
function myOutputHandler(A,B,kp)
    
    // write header line
    fprintf(_fd, '%SQ greatDesign.sq\n\n');
    
    // write variables
    dumpvar(_fd, 'A', A);
    dumpvar(_fd, 'B', B);
    dumpvar(_fd, 'gain', kp);  // different name
    
    // write current subplot settings
    dumpvar(_fd, '_plots', subplots);
    dumpvar(_fd, '_plotprops', subplotprops);
    if ~isempty(subplotpos)
        dumpvar(_fd, '_plotpos', subplotpos);
    end

function (A,B,kp) = myInputHandler()
    
	// read and interpret SQD file into struct s
	str = fread(_fd, inf, '*char');
	s = sandbox(str);
	
    // map the SQD variables to the SQ variable
    kp = s.gain;
    
    // check the validity of the transfer function
    if length(s.A) >= length(s.B)
        dialog(['The transfer function of the system B/A ',
            'must be strictly causal.');
        cancel;
    end
	A = s.A;
	B = s.B;
    
    // restore subplot settings
    subplots(s._plots);
    subplotprops(s._plotprops);
    subplotpos(s._plotpos);
@}

The contents of what might be a data file can also be written in the data block of a SQ file. The user may find more convenient to save the data in the SQ file itself, either to have an SQ file with new default values or to distribute it to other people. The data block should be at the end of the SQ file, so that all the variables and the functions used by the input handler are defined. You can write it manually, but its purpose is to be written by Sysquake when the user chooses to save the data as an SQ file. Its syntax is

data
{@
contents of a data file
@}

Error Messages

Here is the list of error messages; some of them may appear in a message box when you read a bad file, but many are internal errors. LME errors are listed in the LME Reference chapter and are caused by a bad function either at compile time or at execution time.

Exhausted resources
Not enough memory for the current operation.
Too small name buffer
Not enough memory for the table of variable names.
No more name slot
Too many variable names.
Too small Sysquake buffer
Not enough memory to launch Sysquake.
Not enough memory for decoding SQ file
Class file too complex.
Too small Undo buffer
Not enough memory to create the Undo structures.
Too many variables for the Undo buffer
Undo structures too small for the large number of variables.
Variable too large for the Undo buffer
The new value given to a variable is too large.
Variable not found
Attempt to retrieve a variable which has not been defined (should never occur).
Variable already exists
Attempt to redefine a variable.
Standard variable unexpected here
A standard variable, such as _x1, is not supported here.
Syntax error in class file
Unbalanced quotes or parenthesis, missing element, or other syntax error in the class file.
Bad block of text
Block of text (such as a block of function definitions) without end mark.
Bad variable definition
The variable keyword is not followed by a valid variable name.
Bad function definition
The function keyword is not followed by a valid function call.
Undefined element
The keyword is unknown.
Nonexistent set of variables in the Undo buffer
Attempt to revert to an undo state which is not available.
Not a data file
The file does not begin with the expected "% SQ" characters.
Cannot undo
Too many attempts to undo.
Cannot redo
Too many attempts to redo.