## A Basic Guide to using IupLua

by Steve Donovan

IupLua is a cross-platform kit for creating GUI applications in Lua. There are particularly powerful facilities for getting user input that don't require complicated coding, so it is particularly good for utility scripts.

Attributes are an important concept in IUP. You set and get them just like table fields, but they are different from fields in several crucial ways. First, case is not significant, `SIZE` is just as good as `size` (but try to be consistent!). Second, writing to a non-existent attribute will not give you an error, so proof-read carefully. Third, writing to an attribute often causes some action; e.g the `visible` attribute of controls can be used to hide them. It is best to think of them as a special kind of function call.

Functions which create IupLua objects (i.e. constructors) take tables as arguments. Lua allows you to drop the usual parentheses in such a case, but remember that something like `iup.fill{}` is not the same as `iup.fill()`; it is actually short for `iup.fill({})`. A Lua table can contain an array-like part (just items separated by commas) and a map-like part (attribute-value pairs); the convention is to put the array part first, and separate the map part from it with a semicolon. (See Attributes/Guide/IupLua in the Manual for a good discussion.)

All the examples presented here and some utilities can be found at the "misc" folder in the IupLua examples.

## Simple Output

Even simple scripts need to give the user some feedback. Otherwise people get anxious and start worrying if their files really have been backed up, for example. This is easy in IUPLua, and takes exactly one line. Note that all IUP scripts must at least have a `require 'iuplua'` statement at the begining:

    require( "iuplua" )

    iup.Message('YourApp','Finished Successfully!')

Of course, many operations require confirmation from the user. `iup.Alarm` is designed for this:

    require( "iuplua" )

    b = iup.Alarm("IupAlarm Example", "File not saved! Save it now?" ,"Yes" ,"No" ,"Cancel")

    -- Shows a message for each selected button
    if b == 1 then
      iup.Message("Save file", "File saved sucessfully - leaving program")
    elseif b == 2 then
      iup.Message("Save file", "File not saved - leaving program anyway")
    elseif b == 3 then
      iup.Message("Save file", "Operation canceled")
    end

Like `iup.Message`, the first parameter appears in the title bar of the dialog box, the second parameter appears above the buttons, but `iup.Alarm` allows you to specify a number of buttons. The return code will then tell you which button has been pressed, starting at 1 (which is always the Lua way.)

## Simple Input

### Asking for a Filename

The most common thing an interactive script will require from a user is a file, or set of files. For simple cases, `iup.GetFile` will do the job:

    require( "iuplua" )

    f, err = iup.GetFile("*.txt")
    if err == 1 then
      iup.Message("New file", f)
    elseif err == 0 then
      iup.Message("File already exists", f)
    elseif err == -1 then
      iup.Message("IupFileDlg", "Operation canceled")
    end

This will present you with the standard Windows File Open dialog box, and allow you to either choose a filename, or cancel the operation. Notice that this function returns two values, the filename and a code. The code will tell you whether the file does not exist yet (if for instance you typed a new filename into the file dialog box.)

### Asking for Multiline Text

The simplest way of getting general text is to use `iup.GetText`:

    require 'iuplua'

    res = iup.GetText("Give me your name","")

    if res ~= "" then
        iup.Message("Thanks!",res)
    end

Using this dialog, you can enter as many lines as you like, and press OK.

### Asking for a Single String, or Number

A better option for asking for a single string is the very versatile `iup.GetParam`:

    require( "iuplua" )
    require( "iupluacontrols" )

    res, name = iup.GetParam("Title", nil,
        "Give your name: %s\n","")

    iup.Message("Hello!",name)

This has two advantages over plain `GetText`; you can give a prompt line, and you can press Enter after entering text.

The `%s` code requires some explanation. Although you might at first think it is a C-style formating code, as you would use in `string.format`, it actually describes how the value is going to edited; `%s` here merely means that a regular text box is used; if you had used `%m`, then a multiline edit box (like that used by `iup.GetText`) would be used.

If there is a limited set of choices, then the `%l` format is useful:

    res, prof = iup.GetParam("Title", nil,
        "Give your profession: %l|Teacher|Explorer|Engineer|\n",0)

Note the `|item1|item2|...|` list after the `%l` format; these are the choices presented to the user. The initial value you give it, and the value you receive from it, are going to be an index into this list of choices. Somewhat confusingly, they start at 0 (which is not the Lua way!) So in this case, `0` means that 'Teacher' is to be selected, and if I then selected 'Engineer', the resulting value of `prof` would be 2.

The `%i` code allows you to enter an integer value, with up/down arrows for incrementing/decrementing the value.

    require( "iuplua" )
    require( "iupluacontrols" )

    res, age = iup.GetParam("Title", nil,
        "Give your age: %i\n",0)

    if res ~= 0 then    -- the user cooperated!
        iup.Message("Really?",age)
    end

## Dialogs

### Constructing General Layouts

`GetParam` is a very versatile facility for asking for data, but it is not very interactive. In general, you want to present something back to the user that is more complicated than a simple message. Up to now we have used the predefined dialogs available to IupLua; it is now time to go beyond that and examine custom dialogs. The structure of a simple IupLua program is straightforward:

    require 'iuplua'

    text = iup.multiline{expand = "YES"}

    dlg = iup.dialog{text; title="Simple Dialog",size="QUARTERxQUARTER"}

    dlg:show()

    iup.MainLoop()

A multiline edit control is created, and put inside a window frame with a given size, which is then made visible with the `show` method. We then enter the main loop of the application with `MainLoop`, which will only finish when the window is closed.

Controls are also windows, but without the frame and decorations of a top-level window; they are always meant to be inside some window frame or other container. We set the `expand` attribute of `multiline` to force it to use up all the available space in the frame, so that it takes its size from its container. The dialog's `size` attribute is a string of the form "XSIZExYSIZE", where sizes can be expressed as fractions of the desktop window size, in this case a quarter of the width and height. (You can of course also use numerical sizes like "100x301" but these will not always scale well on displays with different resolutions. See Attributes/Common/SIZE in the manual for these units.)

It's good to pause a moment to look at the resulting application in action; it is fully responsive and you can enter text, paste, etc. into the edit control. Common keyboard shortcuts like `Ctrl+V` and `Ctrl+C` work as expected. All this functionality comes with the windowing system you are currently using. On my system, Task Manager shows that this program uses 3.8 Meg of memory, and an instance of Notepad uses 3.3 Meg, which represents all the common code necessary to support a simple GUI application; you are not actually paying much for using IupLua at all. The equivalent C program using the Windows API would be about 150 lines, so the gain in programmer efficiency is tremendous!

Of course, there is not much interaction possible with such a simple program. To make a program respond to the user we define callbacks which the system calls when some event takes place. For example, we can put a button control in the dialog, and define its `action` callback:

    require 'iuplua'

    btn = iup.button{title = "Click me!"}

    function btn:action ()
        iup.Message("Note","I have been clicked!")
        return iup.DEFAULT
    end

    dlg = iup.dialog{btn; title="Simple Dialog",size="QUARTERxQUARTER"}

    dlg:show()

    iup.MainLoop()

This is perfectly responsive, although not very useful! The button sizes itself to its natural size since `expand` is not set (try setting `expand` to see the button fill the whole window frame.) Callbacks usually return the special value `iup.DEFAULT`, although in IupLua this is not really necessary.

`dialog` takes only one control, so IupLua defines containers in which you can pack as many controls as you like. Here `vbox` is used to pack two buttons into the dialog vertically (To save space I'm leaving out the 'dlg:show...' common code at the bottom)

    btn1 = iup.button{title = "Click me!"}
    btn2 = iup.button{title = "and me!"}

    function btn1:action ()
        iup.Message("Note","I have been clicked!")
    end

    function btn2:action ()
        iup.Message("Note","Me too!")
    end

    box = iup.vbox {btn1,btn2}

    dlg = iup.dialog{box; title="Simple Dialog",size="QUARTERxQUARTER"}

This does the job, although the buttons are sized differently according to their contents; this program would not win any design contests! Still, you now have two commands in your application. You can actually get a more pleasing result by using a horizontal packing box (`hbox`) and specifying a non-zero gap between the buttons:

    box = iup.hbox {btn1,btn2; gap=4}

You can nest boxes as much as you like, which is the way to construct more complicated layouts. Here are our horizontal buttons packed vertically with a multiline edit control:

bbox = iup.hbox {btn1,btn2; gap=4} text = iup.multiline{expand = "YES"} vbox = iup.vbox{bbox,text}

dlg = iup.dialog{vbox; title="Simple Dialog",size="QUARTERxQUARTER"}

We have effectively implemented a crude but functional toolbar:

A labeled frame can be put around a control using `iup.frame`:

    edit1 = iup.multiline{expand="YES",value="Number 1"}
    edit2 = iup.multiline{expand="YES",value="Number 2?"}

    box = iup.hbox {iup.frame{edit1;Title="First"},iup.frame{edit2;Title="Second"}}

A useful way to present various views to a user is to put them in tabs. This places each control in a separate page, accessible through the tabbar at the top. Notice in this example that the titles of the tab pages are actually set as attributes of the pages through `tabtitle`. This is not one of the standard IUP controls (see Controls/Additional in the manual) so we also need to bring in the `iupluacontrols` library.

    require( "iupluacontrols" )

    edit1 = iup.multiline{expand="YES",value="Number 1",tabtitle="First"}
    edit2 = iup.multiline{expand="YES",value="Number 2?",tabtitle="Second"}

    tabs = iup.tabs{edit1,edit2,expand='YES'}

### Timers and Idle Processing

Sometimes a program needs to wake up and perform some operation, such as a scheduled backup or an autosave operation. IupLua provides timers for this purpose. (Note at this point that there is no reason why you can't have `print` in a IupLua application; sometimes there is no better way to track what's going on. But on Windows you do have to run the program using the regular lua.exe, not wlua.exe.)

    -- timer1.lua

    require "iuplua"

    timer = iup.timer{time=500}

    btn = iup.button {title = "Stop",expand="YES"}

    function btn:action ()
        if btn.title == "Stop" then
            timer.run = "NO"
            btn.title = "Start"
        else
            timer.run = "YES"
            btn.title = "Stop"
        end
    end

    function timer:action_cb()
        print 'timer!'
    end

    timer.run = "YES"

    dlg = iup.dialog{btn; title="Timer!"}
    dlg:show()
    iup.MainLoop()

After a timer has been started by setting its `run` attribute to "YES", it will continue to call `action_cb` using the given time in milliseconds. Notice that it is important to set the timer going only after the callback has been defined. It is perfectly permissable to switch a timer off in the callback, which is how you can perform a single action after waiting for some time.

It is a well-known fact that computers spend most of the time doing very little, waiting for incredibly slow humans to type something new. However, when a computer is actually doing intense processing, users become impatient if not told about progress. If you do your lengthy processing directly, then the windows of the application become unresponsive. The proper way to organize such work is to do it when the system is idle.

IupLua provides a gauge control which is intended to show progress; this little program shows that even when the computer is almost completely preoccupied doing work, it is still keeping the user informed and in fact the window remains useable, although a little slow to respond.

    -- idle1.lua
    require "iuplua"
    require "iupluacontrols"

    function do_something ()
        for i=1,6e7 do end
    end

    gauge = iup.gauge{show_text="YES"}

    function idle_cb()
        local value = gauge.value
        do_something()
        value = value + 0.1
        if value > 1.0 then
            value = 0.0
        end
        gauge.value = value
        return iup.DEFAULT
    end

    dlg = iup.dialog{gauge; title = "IupGauge"}

    iup.SetIdle(idle_cb)

    dlg:showxy(iup.CENTER, iup.CENTER)

    iup.MainLoop()

### Lists

It is easy to display a list of values in IupLua. The values can be directly specified in the `iup.list` constructor, like so:

    -- list1.lua
    require "iuplua"

    list = iup.list {"Horses","Dogs","Pigs","Humans"; expand="YES"}

    dlg = iup.dialog{list; title="Lists"}
    dlg:show()
    iup.MainLoop()

(Remember that the single argument to these constructors is just a Lua table, which you can construct in any way you choose, say by reading the values from a file.)

Tracking selection changes is straightforward:

    function list:action(t,i,v)
        print(t,i,v)
    end

Now, as I move the selection through the list, from the start to the finish, the output is:

    Horses  1       1
    Horses  1       0
    Dogs    2       1
    Dogs    2       0
    Pigs    3       1
    Pigs    3       0
    Humans  4       1

So `v` is 1 if we are selecting an item, 0 if we are deselecting it; `i` is the one-based index in the list, and `t` is the actual string value. If you want to associate some other data with each value, then all you need to do is keep a table of that data and look it up using the index `i`.

To register a double-click is a little more involved. There is (as far as I can tell) no way to detect whether a double-click has happened in the `action` callback. So we track the selection manually; if two selection events for a given item happen consecutively, then that is understood to be a double-click. It ain't pretty, but it works (except perhaps for the valid case of a person wanting to double-click the same item repeatedly):

    local lastidx,doubleclick

    function on_double_click (t,i)
        print(t,i)
    end

    function list:action(t, i, v)
        if v ~= 0 then
            if lastidx == i and doubleclick ~= i then
                on_double_click(t,i)
                doubleclick = i
            end
            lastidx = i
        end
    end

Once a list has been created, how does one change the contents? The answer is that the list object behaves like an array. For example, to fill a list with all the entries in a directory, I can use this function:

    function fill (path)
        local i = 1
        for f in lfs.dir(path) do
            list[i] = f
            i = i + 1
        end
        list[i] = nil
    end

Note that this does not mean that a list object is a table. In particular, you have to explicitly set the end of the list of elements by setting a nil value just after the end.

### Trees

The most flexible way to present a hierarchy of information is a tree. A tree has a single root, and several branches. Each of these branches may have leaves, and other branches. All of these are called nodes. Thinking of a family tree, a node may have child nodes, which all share the same parent node.

A good example of this in everyday computer experience is a filesystem, where the leaves are files and the branches are directories. Lua tables naturally express these kind of nested structures easily, and in fact it is easy to present a Lua table as a tree, where array items are leaves, and the branches are named with the special field `branchname`:

    require 'iuplua'
    require 'iupluacontrols'

    tree = iup.tree{}
    tree.addexpanded = "NO"

    list = {
      {
        "Horse",
        "Whale";
        branchname = "Mammals"
      },
      {
        "Shrimp",
        "Lobster";
        branchname = "Crustaceans"
      },
      {
        branchname = "Birds"
      },
      branchname = "Animals"
    }

    iup.TreeAddNodes(tree, list)

    f = iup.dialog{tree; title = "Tree Test"}

    f:show()

    iup.MainLoop()

This example begins with the branches 'collapsed', and you will have to explicitly expand them with a mouse click. By default, trees are presented in their fully expanded form; try taking out the fourth line that sets the `addexpanded` attribute of the tree object. Note that branches can be empty!

Tree operations are naturally more complicated than list operations, but there is a callback which happens when a node is selected or unselected. Add this to the example:

    function tree:selection_cb (id,iselect)
        print(id,iselect,tree.name)
    end

You will see that `iselect` is 0 for the unselection operation, and 1 for selection; id is a tree node index. These indices are always in order of appearance in a tree, starting at 0 for the root node. The `name` attribute of the tree object is the text of the currently selected node.

A pair of useful callbacks are `branchopencb` and `branchclosecb`. If you were displaying a potentially very large tree (like your computer's filesystem) then it would be inefficient to create the whole tree at once, especially considering that you would normally be only interested in a small part of that tree. Trapping `branchopencb` allows you to add child nodes to your selected node before it is expanded. `executeleafcb` is called when you double-click on a leaf, as if you were running a program in a file explorer.

In itself, the id is not particularly useful. The id order is always the same in the tree, so as nodes get added and removed, the id of a particular node will change. Generally, there is going to be some deeper data associated with a node. On a filesystem, a node represents a full path to a file or directory, or there may be an ip address associated with a computer name. IUP provides you with a way to associate arbitrary data with nodes even if the id changes. But to use this you will have to understand how to build up a tree from scratch - `TreeAddNodes` is very convenient, but won't help you if you have to add nodes later. Replace the definition of `list` and the call to `TreeAddNodes` with this code:

    tree.name = "Animals"
    tree.addbranch = "Birds"
    tree.addbranch = "Crustaceans"
    tree.addbranch = "Mammals"

You will get the top level branches of the tree; notice that they are specified in reverse order, since nodes are always added to the top. Also note the curious way in which the `addbranch` attribute is used. For a start, it is write-only, and the effect of setting a value to it is to add a new branch to the currently selected node. By default, this starts out as the root (which is set using the `name` attribute) The id of the root is always 0; when we add "Birds", the new branch has id 1, again when we add "Crustaceans" the new branch also has id 1 - by which time "Birds" has moved to id 2, further down the tree.

To add leaves, a similar process:

    tree.name = "Animals"
    tree.addbranch = "Mammals"
    tree.addleaf1 = "Whale"

The `addleaf` attribute works like `addbranch`, and both of them can take an extra parameter, which is the id of the node to add to. In this case, "Whale" is a child leaf of the "Mammals" branch, which has id 1 at this stage. This new leaf gets an id of 2, which is one more than the parent. So this gives us a way to build up arbitrary trees, knowing the id at each point. IUP provides a function TreeSetUserId which can associate a Lua table with a node id. We can choose to put a string value inside this table, but it really can contain anything. Here is the first example, using some helper functions to simplify matters:

    -- testtree2.lua

    require 'iuplua'
    require 'iupluacontrols'
    tree = iup.tree{}

    function assoc (idx,value)
        iup.TreeSetUserId(tree,idx,{value})
    end

    function addbranch(self,label,value)
        self.addbranch = label
        assoc(1,value or label)
    end

    function addleaf(self,label,value)
        self.addleaf1 = label
        assoc(2,value or label)
    end

    tree.name = "Animals"
    addbranch(tree,"Birds")
    addbranch(tree,"Crustaceans")
    addleaf(tree,"Shrimp")
    addleaf(tree,"Lobster")
    addbranch(tree,"Mammals")
    addleaf(tree,"Horse")
    addleaf(tree,"Whale")

    function dump (tp,id)
        local t = iup.TreeGetUserId(tree,id)
        -- our string data is always the first element of this table
        print(tp,id,t and t[1])
    end

    function tree:branchopen_cb(id)
        dump('open',id)
    end

    function tree:selection_cb (id,iselect)
        if iselect == 1 then dump('select',id) end
    end

    f = iup.dialog{tree; title = "Tree Test"}

    f:show()

    iup.MainLoop()

There is a corresponding function TreeGetUserId which accesses the table associated with the node id. There is also a function TreeGetId which will return the id, given the unique table associated with it. You can use this to programmatically select a tree node given its data by setting the `value` attribute to the returned id.

Now let's do something interesting with a tree control, a simple file browser. It is straightforward to get the files and directories contained within a directory:

    require 'lfs'

    local append = table.insert

    function get_dir (path)
        local files = {}
        local dirs = {}
        for f in lfs.dir(path) do
            if f ~= '.' and f ~= '..' then
                if lfs.attributes(path..'/'..f,'mode') == 'file' then
                    append(files,f)
                else
                    append(dirs,f)
                end
            end
        end
        return files,dirs
    end

We ignore '.' and '..' (the current and parent directory respectively) and check the mode to see if we have file or a directory; this requires the full path to be passed to `attributes`. This function returns two separate tables containing the names of the files and directories.

It is useful to define two helper functions for setting and getting data to be associated with the tree nodes:

    tree = iup.tree {}

    function set (id,value,attrib)
        iup.TreeSetUserId(tree,id,{value,attrib})
    end

    function get(id)
        return iup.TreeGetUserId(tree,id)
    end

Filling a tree with the contents of a directory is straightforward. We want the directories before the files, so we put them in last; nodes must be added in reverse order! The id of the new nodes will always be `id+1` where `id` is going to be the directory which we are filling. The fullpath plus a field indicating whether we are a directory is associated with each new item:

    function fill (path,id)
        local files,dirs = get_dir(path)
        id = id + 1
        local state = "STATE"..id
        for i = #files,1,-1 do -- put the files in reverse order!
            tree.addleaf = files[i]
            set(id,path..'/'..files[i])
        end
        for i = #dirs,1,-1 do -- ditto for directories!
            tree.addbranch = dirs[i]
            set(id,path..'/'..dirs[i],'dir')
            tree[state] = "COLLAPSED"
        end
    end

By default, the directory branches will be created in their expanded form, so we use the `STATE` attribute to force them into their collapsed state. Normally you would say this in Lua like so `state2 = "COLLAPSED"` but here we build up the appropriate attribute string with the given id and use array indexing to set the tree attribute.

Just calling `fill('.',0)` and putting the tree into a dialog as usual will give you a directory listing of the current directory! But it would be cool if expanding a directory node would automatically fill that node; it would obviously be wasteful to fill the whole tree at startup, since your filesystem contains thousands of files. The `branchopencb` callback is called when a user tries to expand a directory. We use this to fill the directory with its contents, but only on the _first time that we expand this node:

    function tree:branchopen_cb(id)
        tree.value = id
        local t = get(id)
        if t[2] == 'dir' then
            fill(t[1],id)
            set(id,t[1],'xdir')
        end
    end

This is why directories need to be specially marked, so we can tell later whether we have actually generated the contents of that directory!

The first statement of this function makes the node we are opening to be the selected node of the tree. (Although we are passed the correct id of the node, it seems to be necessary to perform this step to make things work correctly.)

See `directory.lua` in the examples folder.

### Menus

Any application that can perform a number of operations needs a menu. These are not difficult to create in Iuplua, although it can be a little tedious to set up. The basic idea is this: create some items, make a menu out of these items, and set the `menu` attribute of the dialog. The items have an associated `action` callback, which actually performs the operation.

    -- simple-menu.lua

    require( "iuplua" )

    -- Creates a text, sets its value and turns on text readonly mode
    text = iup.text {readonly = "YES", value = "Show or hide this text"}

    item_show = iup.item {title = "Show"}
    item_hide = iup.item {title = "Hide"}
    item_exit = iup.item {title = "Exit"}

    function item_show:action()
      text.visible = "YES"
      return iup.DEFAULT
    end

    function item_hide:action()
      text.visible = "NO"
      return iup.DEFAULT
    end

    function item_exit:action()
      return iup.CLOSE
    end

    menu = iup.menu {item_show,item_hide,item_exit}

    -- Creates dialog with a text, sets its title and associates a menu to it
    dlg = iup.dialog{text; title="Menu Example", menu=menu}

    -- Shows dialog in the center of the screen
    dlg:showxy(iup.CENTER,iup.CENTER)

    iup.MainLoop()

A menu may contain items and submenus. This example shows a small function which makes creating arbitrarily complicated menus easier:

    -- menu.lua

    require( "iuplua" )

    function default ()
        iup.Message ("Warning", "Only Exit performs an operation")
        return iup.DEFAULT
    end

    function do_close ()
        return iup.CLOSE
    end

    mmenu = {
        "File",{
            "New",default,
            "Open",default,
            "Close",default,
            "-",nil,
            "Exit",do_close,
        },
        "Edit",{
            "Copy",default,
            "Paste",default,
            "-",nil,
            "Format",{
                "DOS",default,
                "UNIX",default
            }
        }
    }

    function create_menu(templ)
        local items = {}
        for i = 1,#templ,2 do
            local label = templ[i]
            local data = templ[i+1]
            if type(data) == 'function' then
                item = iup.item{title = label}
                item.action = data
            elseif type(data) == 'nil' then
                item = iup.separator{}
            else
                item = iup.submenu {create_menu(data); title = label}
            end
            table.insert(items,item)
        end
        return iup.menu(items)
    end

    -- Creates a text, sets its value and turns on text readonly mode
    text = iup.text {value = "Some text", expand = "YES"}

    -- Creates dialog with a text, sets its title and associates a menu to it
    dlg = iup.dialog {text; title = "Creating Menus With a Table",
          menu = create_menu(mmenu), size = "QUARTERxEIGHTH"}

    -- Shows dialog in the center of the screen
    dlg:showxy (iup.CENTER,iup.CENTER)

    iup.MainLoop()

The function `create_menu` does all the work; we provide it with a Lua table containing pairs of values; the first value of a pair is always a string, and will be the label. The second value can either be a function, in which case it represents an item to be associated with a callback, or `nil`, which means that it's a separator, or otherwise must be a table, which represents a submenu. It is a nice example of how recursion can naturally handle nested structures like menus, and how Lua's flexible table definitions can make specifying such structures easy. This useful function is available in the `iupx` utility library as `iupx.menu`.

### Plotting Data

Many kinds of numerical data are best seen as X-Y plots. `iup.plot` is a control which can show several kinds of plots; you can have lines between points, show them as markers, or both together. Several series (or datasets) can be shown on a single plot, and a simple legend can be shown. The plot will automatically scale to view all datasets, but the default minimum and maximum x and y values can be changed. It is even possible to select points and edit them on the plot.

A simple plot is straightforward:

    -- plot1.lua
    require( "iuplua" )
    require( "iupluacontrols" )
    require( "iuplua_plot51"  )

    plot = iup.plot{TITLE = "A simple XY Plot",
                        MARGINBOTTOM="35",
                        MARGINLEFT="35",
                        AXS_XLABEL="X",
                        AXS_YLABEL="Y"
                        }

    iup.PlotBegin(plot,0)
    iup.PlotAdd(plot,0,0)
    iup.PlotAdd(plot,5,5)
    iup.PlotAdd(plot,10,7)
    iup.PlotEnd(plot)

    dlg = iup.dialog{plot; title="Plot Example",size="QUARTERxQUARTER"}

    dlg:show()

    iup.MainLoop()

Creating a dataset involves calling `PlotBegin`, a number of calls to `PlotAdd` to add data points, and finally a call to `PlotEnd`. You can create multiple datasets (or series) using multiple begin/end calls, and can of course use loops to add points:

    iup.PlotBegin(plot,0)
    for x = -2,2,0.01 do
        iup.PlotAdd(plot,x,math.sin(x))
    end
    iup.PlotEnd(plot)

    iup.PlotBegin(plot,0)
    for x = -2,2,0.01 do
        iup.PlotAdd(plot,x,math.cos(x))
    end
    iup.PlotEnd(plot)

    plot.DS_LINEWIDTH = 3

A limitation of the `plot` library is that it does not choose appropriate sizes for the plot margins. So I've had to set the bottom and left margins (in pixels) to properly accomodate the axes and their titles. As with all IupLua attributes, you can choose to make them upper case if you like; a full list is found in the manual under Controls/Additional/IupPlot. Some of these attributes refer to the plot as a whole, some to the current dataset. For instance, setting `GRID` to "YES" will draw gridlines for both axes, but if we set `DS_LINEWIDTH` to 3 after the construction of the cosine dataset, then only that line is affected.

Some attributes affect others. `DS_MODE` is used to specify how to draw the dataset; it can be "LINE", "BAR", (for a bar chart) "MARK" (just for marks) or "MARKLINE" (for lines and marks). But it has to be set before any of the other `DS_` attributes like `DS_MARKSIZE`, etc. In another case, you will often find it useful to set an explicit minimum y value by setting `AXS_YMIN`. But it will only take effect if `AXIS_YAUTOMIN` has been set to "NO" to disable auto scaling.

As with menus, making a Lua-friendly wrapper around an API is not difficult and can be very labour-saving. It would be clearer if we could work with the plot object in a more object-oriented way:

        plot:Begin()
        for i = 1,#xvalues do
                plot:Add(xvalues[i],yvalues[i])
        end
        plot:End()

And for the common case where you have arrays of values, it would be convenient to be able to say:

    plot:AddSeries({{0,1.5},{5,4.5},{10,7.6}},{DS_MODE="MARK"})

Here is a function which wraps the `Plot` API:

    function create_plot (tbl)
        -- don't need to remember this anymore!
        require( "iuplua_plot51"  )

        -- the defaults for these values are too small, at least on my system!
        if not tbl.MARGINLEFT then tbl.MARGINLEFT = 30 end
        if not tbl.MARGINBOTTOM then tbl.MARGINBOTTOM = 35 end

        -- if we explicitly supply ranges, then auto must be switched off for that direction.
        if tbl.AXS_YMIN then tbl.AXS_YAUTOMIN = "NO" end
        if tbl.AXS_YMAX then tbl.AXS_YAUTOMAX = "NO" end
        if tbl.AXS_XMIN then tbl.AXS_XAUTOMIN = "NO" end
        if tbl.AXS_XMAX then tbl.AXS_XAUTOMAX = "NO" end

        local plot = iup.plot(tbl)
        plot.End = iup.PlotEnd
        plot.Add = iup.PlotAdd
        function plot.Begin ()
            return iup.PlotBegin(plot,0)
        end

        function plot:AddSeries(xvalues,yvalues,options)
            plot:Begin()
            -- is xvalues a table of (x,y) pairs?
            if type(xvalues[1]) == "table" then
                -- because there's only one data table, the next must be options
                options = yvalues
                for i,v in ipairs(xvalues) do
                    plot:Add(v[1],v[2])
                end
            else
                for i = 1,#xvalues do
                    plot:Add(xvalues[i],yvalues[i])
                end
            end
            plot:End()
            -- set any series-specific plot attributes
            if options then
                -- mode must be set before any other attributes!
                if options.DS_MODE then
                    plot.DS_MODE = options.DS_MODE
                    options.DS_MODE = nil
                end
                for k,v in pairs(options) do
                    plot[k] = v
                end
            end
        end

        function plot:Redraw()
            plot.REDRAW='YES'
        end
        return plot
    end

This function creates a `Plot` object as usual, but supplies some more sensible defaults for the margins, makes setting things like `AXS_XMAX` also set `AXS_XAUTOMAX`, and adds some new methods to the object. Of these, `AddSeries` is the interesting one. It allows you to specify the data in two forms; either as two arrays of x and y values, or as a single array of x-y pairs. It also allows optionally setting `DS_` attributes, taking care to set the plot mode before any other attributes. In this way, the actual details can be hidden away from the programmer, who has then less things to worry about.

Given this function, we can write a little program which plots some points and draws the linear least-squares fit between them:

    -- simple-plot.lua

    local xx = {0,2,5,10}
    local yy = {1,1.5,6,8}

    function least_squares (xx,yy)
        local xsum = 0.0
        local ysum = 0.0
        local xxsum = 0.0
        local yysum = 0.0
        local xysum = 0.0
        local n = #xx
        for i = 1,n do
            local x,y = xx[i], yy[i]
            xsum = xsum + x
            ysum = ysum + y
            xxsum = xxsum + x*x
            yysum = yysum + y*y
            xysum = xysum + x*y
        end
        local m = (xsum*ysum/n - xysum )/(xsum*xsum/n - xxsum)
        local c = (ysum - m*xsum)/n
        return m,c
    end

    local m,c = least_squares(xx,yy)

    function eval (x) return m*x + c end

    local plot = create_plot {TITLE = "Simple Data",AXS_YMIN=0,GRID="YES"}

    -- the original data
    plot:AddSeries(xx,yy,{DS_MODE="MARK",DS_MARKSTYLE="CIRCLE"})

    -- the least squares fit
    local xmin,xmax = xx[1],xx[#xx]
    plot:AddSeries({xmin,xmax},{eval(xmin),eval(xmax)})

`create_plot` is so useful that I've packaged it as part of the `iupx` library as `iupx.plot`. A new pseudo-attribute has been introduced, `AXS_BOUNDS`, which is a table of four values `{xmin,ymin,xmax,ymax}`. This example shows that very different ranges can happily exist on the same plot:

    -- plot5.lua

    require "iupx"

    plot = iupx.plot {TITLE = "Simple Data", AXS_BOUNDS={0,0,100,100}}

    plot:AddSeries ({{0,0},{10,10},{20,30},{30,45}})
    plot:AddSeries ({{40,40},{50,55},{60,60},{70,65}})

    iupx.show_dialog{plot; title="Easy Plotting",size="QUARTERxQUARTER"}