# How to add commands to med

There are several steps to adding a command to med. Not all of these steps are needed for a given task.

Briefly, one defines commands in the file `lib/med_gui/commands_med.tcl` says what menus and toolbars they go in in the file `lib/med_gui/menus_med.tcl`, and actually implements the commands in other files : the GUI part goes into the `lib/med_gui` area and the batch part goes into `lib/med_batch`. Finally language-specific bindings can be given in the file `language_text_XXX.tcl` for the given language.

### Adding the name of the command to the menu structure.

The file `lib/med_gui/menus_med.tcl` has a list of all the menus, hotkeys, and toolbars available in med. There are 3 types of tcl statements that can used in this file.

command_make_menu name activedata side menu-spec

This defines a pull-down menu that appears in the menu bar at the top. The arguments are as follows. name is any string, which should be enclosed in ""

activedata is a list of variables that determine whether the menu is active or not. If it's "" then the menu is always active. If it's the name of one variable, for example data_available(geom), then the menu is active only when that variable is set. More complex options are possible - please see the documentation for the `guibase/forms.tcl` file for more details.

The variables that can be used in activedata can be any variable that is known to the GUI interpreter but these are the common ones:

- data_available(unstruct) - there is an unstructured mesh loaded
- data_available(struct) - there is a structured mesh loaded
- data_available(mesh) - there is some kind of mesh loaded
- data_available(geom) - there is some CAD data loaded
- data_available(geom_facet) - there is faceted CAD data loaded
- enable_feature(XXX) - feature XXX has been enabled

The other options for the active string are disabled, which means to skip it altogether, and always, which means the same thing as ""

side is either left or right. This determines which side of the menu bar the menu will go. Also the word button can follow left or right which means to take the name of the menu as the menu spec. This is only used for the Help button so far, e.g.:

`command_make_menu "Help" "" "right button" {}`

menu-spec is a list of items that go into the menu. Each item can be of several forms:

{ "Command name" }

This is the name of a command that is defined in the `commands_med.tcl` file, as described below.

separator

This makes a separator line.

{ "Sub-menu name" activedata cascade sub-menu-spec }

This creates a cascade sub-menu. The name could be anything. The activedata is as described above. The sub-menu-spec is the same as the menu-spec definition.

{ "Sub-menu" activedata variable_cascade variable-name { { value "Name" sub-menu-spec } ... } }

This is similar to a cascade menu, but depending on the value of the variable given by variable-name, the label on the menu entry changes and also the sub-menu that is tied to it is modified.

disabled any stuff...

This disables the entry.

Here is an example that illustrates all these types.

    command_make_menu "File" "" left {
        { "Open project" }
        separator
        { "Project dir" "" cascade {
    	{ "Copy project" }
        } }

        { "Create" data_available(geom) variable_cascade geometry_mode {
    	{ surface "Create surface" {
    	    { "Create surface from 4 points" }
    	} }
    	{ curve "Create curve" {
    	    { "Segment curve" }
    	    { "Extract curve from surface" }
            } }
        } }
    }

Note that if command_make_menu is called after the menus are already created, the named menu will be modified to match the new specification.

command_make_toolbar name rownum toolbar-spec

This command creates a toolbar which goes into the second panel at the top.

The name can be anything and is used to reference the toolbar in the Edit toolbars function.

The rownum parameter is the row in which the toolbar should appear. If it is 0 then the toolbar will not be visible (but it can be added or deleted later).

The toolbar-spec is a list of commands that are defined in `commands_med.tcl`

Here is an example:

    command_make_toolbar "File commands" 1 {
        "Open project"
        "Save project"
    }

Alternately, a toolbar entry can be a list with the word cascade followed by an active spec and a list of commands. This creates a sort of pull down menu where one of the items is the menu button and selecting a different one moves that one to the top and then does the command. For example:

    command_make_toolbar "Geometry mode" 1 {
        { cascade data_available(geom)
    	"Geometry mode: surface"
    	"Geometry mode: curve"
    	"Geometry mode: point"
    	"Geometry mode: material"
    	"Geometry mode: loop"
    	"Geometry mode: density"
        }
    }

Note that if command_make_toolbar is called after the menus are already created, the named toolbar will be modified to match the new specification.

command_make_toolbar_space rownum

This command adds a space to the end of the specified row (between the last toolbar written there and the next one).

command_set_hotkeys { key command ... }

One or more key/command pairs can be given. The keys should be the Tk name for a keystroke - e.g. F1 or z or Control-P. The commands are as defined in `commands_med.tcl`. Alternately the commands can be "" which will turn off any existing command for that key. For example:

    command_set_hotkeys {
        F1 "Help"
        z "Zoom in"
        o "Open project"
    }

Note that if command_set_hotkeys is called after the graphics window is created, the new commands will be defined but existing hot keys won't be changed if they are not listed.

### Creating command definitions

In the file `lib/med_gui/commands_med.tcl` there are a list of command_definitions. Any command that is going to be accessible via toolbars, menus, or hot keys must first be defined here. A command definition looks like this:

    command_define "Open project" "Open" open_icon \
        "file_openproject" {
    	Open a new project and load a tetin
    	file and a mesh.
        } med/med-Open always

In this example:

"Open project" is the long name for the command. This is what is used in all the `menus_med.tcl` commands. Every command must have a unique long name.

"Open" is the short name and is used in a cascaded submenu if necessary. Short names do not have to be unique.

open_icon is the name of the icon file (in the `lib/icons` directory, with no .gif or .xbm) that will be used on a toolbar. It may be the word no_icon or "" in which case the short name will be used instead.

"file_openproject" is the command that will get executed. This is a Tcl string that is evaluated in the GUI interpreter (see below).

{Open a new ...} is the bubble help for this command.

med/med-Open is the file name for the html help. It can be no_help if there is no corresponding html file. Also this string can be a list where the second item is a tag inside the html file.

always is where the active string if any goes. Note that the activedata for menus go in the `menus_med.tcl` file, since that is the level where we define menus, and `commands_med.tcl` doesn't know or care what menus the commands will go into. The individual commands have their active data defined here. That means that if a command is active in one menu or toolbar it is active in all.

Note that if command_define must be called for a particular command before that command is used in a menu, toolbar, or hotkey, and if you call it again for the same name it will not affect an existing entry. You could define some commands, create a menu using them, then define new commands and create another menu, though.

### Defining strings for a particular language

In the `language_text` file for a particular language, a list of commands of this form are given:

    command_set_text "Open project" \
        "New long name" \
        "New short name" \
        "New bubble help" \
        "New html string"

Each of these items, if non-empty, overrides the corresponding data given in the command_define entry. However, the long name given originally is still used - the one that appears in command_set_text is used for display purposes only.

If you call command_set_text after the menus, etc have already been created, it will not affect the existing labels and bubble help.

### User customization

In addition to the files `commands_med.tcl` and `menus_med.tcl`, definitions for commands, menus, toolbars, and hotkeys can appear in several other places. In order, they are:

- If an environment variable ICEM_MED_MENUS_FILE is set, definitions will be loaded from that file.
- If there is a file `.icemcfd_menus` in the user's home directory, this will be read.
- If there is a file `.icemcfd_menus` in the current directory, this will be read.
- If a command line option -menus filename is given, then the definitions in this file will be loaded.

Also, if the command line option -no_standard_menus is given to med, it will not read in the standard `menus_med.tcl` file so only the customized definitions the user provides will be available. This also happens if there is an environment variable ICEM_NO_STANDARD_MED_MENUS. The file `commands_med.tcl` is always read, though.

### Writing the command implementation

The med Tcl files are split into two directories. The code in these directories is executed by separate Tcl interps (but still in the same process).

med_gui has files that are used for GUI handling and have access to Tk functions, but not the low-level C++ objects.

`med_batch` contains code that actually does the work and has direct access to the C++/Tcl interfaces, but does not have access to Tk.

The GUI code is responsible for calling the batch code via a set of interface functions. These functions are defined in the batch interp and are prefixed by ic_. So ic_load_unstruct will load an unstructured domain, etc. The ic_ functions are the only interface from the GUI to the batch level.

Also the ic_ functions are the scripting functions available to end users who want to write their own scripts, and the functions that appear in replay files if you are in replay mode.

The connection between the two interpreters, and the hooks needed for doing replay, are set up automatically. If you add a new ic_ function to some file in batch_med it will show up automatically in the GUI interpreter.

Keep in mind that the ic_ functions can take as arguments, and return as results, only names of things, never the internal numerical id's or pointers that might change. (We use the numbers of domains, subfaces, etc in place of names, but these generally don't change arbitrarily so it's possible to do replay with them).

The batch code has a limited set of functions it can call in the GUI interpreter. These are listed in `lib/med_gui/replay_med.tcl,` starting with the line `"set gui_functions_1 {"`. These functions ideally should go away or be cut down substantially, but at least they are all in one place.

If you write a new function, it may be a high-level function, that only interacts with the user and calls some existing ic_ functions to do the work. In this case it can be added to the med_gui directory and the command definition put in commands_med.tcl as described above. If you create a new file remember to cvs add it and put it into the list of files in `med_gui.tcl` that starts with `"set tool_files {"`

You may also have to write new ic_ functions. How to interact with the C++ code is beyond the level of this document - the best suggestion I have is to find an existing function that does something similar and use that as a guideline.

In the `med_batch` directory, all the ic_ functions are in the files ending in `_funcs.tcl`. Extra functions are in the _subs.tcl files. When you add a new ic_ function, before the proc definition there should be a block of comments starting with ## on each line. These are the documentation comments, which will be automatically turned into a html help file when the user requests to view the programmer's manual. The comment text is HTML and should be reasonably descriptive of what the function does and how to call it.

Here is an example of a trivial ic_ function. The last line that sets a member of the array dont_record_command is used to make sure that ic_ commands which don't actually change anything, but just ask for information, don't get put into the replay file.

    ## Does a mesh exist?

    proc ic_uns_is_loaded {} {
        global uns_cur
        return [expr {$uns_cur != ""}]
    }
    set dont_record_command(ic_uns_is_loaded) 1