IupTree (since 3.0)

Creates a tree containing nodes of branches or leaves. Both branches and leaves can have an associated text and image.

The branches can be expanded or collapsed. When a branch is expanded, its immediate children are visible, and when it is collapsed they are hidden.

The leaves can generate an "executed" or "renamed" actions, branches can only generate a "renamed" action.

The focus node is the node with the focus rectangle, marked nodes have their background inverted.

Creation

Ihandle* IupTree(void); [in C] 
iup.tree{} -> (elem: ihandle) [in Lua]
tree() [in LED]

Returns: the identifier of the created element, or NULL if an error occurs.

Attributes

General

ADDEXPANDED
BGCOLOR
CANFOCUS
COUNT
DRAGDROPTREE
EXPAND
FGCOLOR
HIDELINES
HIDEBUTTONS
INDENTATION
RASTERSIZE
SHOWDRAGDROP
SHOWTOGGLE
SPACING
TOPITEM

Nodes

CHILDCOUNT
FGCOLOR
DEPTH
KIND
PARENT
STATE
TITLE
TITLEFONT
TOGGLEVALUE
TOGGLEVISIBLE
USERDATA

Images

IMAGELEAF
IMAGEBRANCHCOLLAPSED
IMAGEBRANCHEXPANDED
IMAGEid
IMAGEEXPANDEDid

Focus Node

VALUE

Marks

MARK
MARKEDid
MARKEDNODES
MARKMODE
MARKSTART

Hierarchy

ADDLEAF
ADDBRANCH
COPYNODE
DELNODE
EXPANDALL
INSERTLEAF
INSERTBRANCH
MOVENODE

Editing

RENAMENODE
RENAMECARET
RENAMESELECTION
SHOWRENAME

Callbacks

SELECTION_CB: Action generated when an node is selected or deselected.
MULTISELECTION_CB: Action generated when multiple nodes are selected with the mouse and the shift key pressed.
BRANCHOPEN_CB: Action generated when a branch is expanded.
BRANCHCLOSE_CB: Action generated when a branch is collapsed.
EXECUTELEAF_CB: Action generated when a leaf is to be executed.
SHOWRENAME_CB: Action generated before a node is renamed.
RENAME_CB: Action generated after a node is renamed.
DRAGDROP_CB: Action generated when an internal drag & drop is executed.
NODEREMOVED_CB: Action generated when a node is about to be removed.
RIGHTCLICK_CB: Action generated when the right mouse button is pressed over a node.
TOGGLEVALUE_CB: Action generated when the toggle's state was changed. The callback also receives the new toggle's state.

Drag & Drop attributes and callbacks are supported, but SHOWDRAGDROP must be set to NO.

Notes

Hierarchy

Branches can contain other branches or leaves. When ADDROOT=Yes the tree has initially one branch, the root. The first node always has id=0 and depth=0. The tree nodes have a sequential identification number (id), starting by the first, with id=0, and increases for each node independent from the node depth. The following picture illustrates the numbering of the nodes in a tree.


Tree nodes and Ids

Since you have to add each node the creation of this tree can be done in several ways because the action attributes ADD* and INSERT* use an existent node to position the new node. The following pseudo code initializes the tree from top to bottom sequentially:

TITLE0 = "Figures"
  ADDLEAF0 = "Other"    // Use the previous node as reference
  ADDBRANCH1 = "triangle"
    ADDLEAF2 = "equilateral"
    ADDLEAF3 = "isoceles"
    ADDLEAF4 = "scalenus"
  INSERTBRANCH2 = "parallelogram"  // Use the previous node at the same depth as reference
    ADDLEAF6 = "square"
    ADDLEAF7 = "diamond"
  INSERTBRANCH6 = "2D"
  INSERTBRANCH9 = "3D"

The following pseudo code initializes the tree from bottom to top sequentially (except for branches), and also uses the focus node:

VALUE = 0  // Set the focus node at the first (default for a new element)
TITLE = "Figures"
ADDBRANCH = "3D"
ADDBRANCH = "2D"
ADDBRANCH = "parallelogram"
ADDLEAF1 = "diamond"
ADDLEAF1 = "square"
ADDBRANCH = "triangle"
ADDLEAF1 = "scalene"
ADDLEAF1 = "isosceles"
ADDLEAF1 = "equilateral"
ADDLEAF = "Other"

Notice that in both cases the initialization of the tree is highly dependent on the order of the operations. Currently we can NOT guarantee the order before mapping to the native system, so the initialization must be performed after the tree is mapped.

Scrollbars are automatically displayed if the tree is greater than its display area.

The first node added to an empty tree will always be the focus node.

Branches may be added in IupLua using a Lua Table, see iup.TreeAddNodes

Manipulation

Node insertion or removal is done by means of attributes. It is allowed to remove nodes and branches inside callbacks associated to opening or closing branches.

This means that the user may insert nodes and branches only when necessary when the parent branch is opened, allowing the use of a larger IupTree without too much overhead. Then when the parent branch is closed the subtree can be removed. But the subtree must have at least 1 node so the branch can be opened and closed, empty branches can NOT be opened.

User Data

The node id does not always correspond to the same node as the tree is modified. For example, an id=2 will always refer to the third node in the tree, so if you add a node before the third node, the node with id=2 will now refer to the new node, and the old node will now have id=3. For that reason, each node can store an user data pointer uniquely identifying the node. To set or retrieve the user data of a node use the USERDATAid attribute, or the Extra Functions below to associate a user data to a node and to find a node given its user data.

Images

IupTree has three types of images: one associated to the leaf, one to the collapsed branch and the other to the expanded branch. Each image can be changed, both globally and individually.

The predefined images used in IupTree can be obtained by means of function IupGetHandle. The names of the predefined images are: IMGLEAF, IMGCOLLAPSED, IMGEXPANDED, IMGBLANK (blank sheet of paper) and IMGPAPER (written sheet of paper). By default:

"IMAGELEAF" uses "IMGLEAF"
"IMAGEBRANCHCOLLAPSED" uses "IMGCOLLAPSED"
"IMAGEBRANCHEXPANDED" uses "IMGEXPANDED"
"IMGBLANK" and "IMGPAPER" are designed for use as "IMAGELEAF"

Simple Marking

It is the default operation mode (MARKMODE=SINGLE). In this mode only one node can be selected.

Multiple Marking

IupTree allows marking several nodes simultaneously using the Shift and Control keys. To use multiple marking set MARKMODE=MULTIPLE. In GTK and Motif multiple nodes can also be selected using a rubber band if SHOWDRAGDROP=NO.

When a user keeps the Control key pressed, the individual marking mode is used. This way, the focus node can be modified without changing the marked node. To reverse a node marking, the user simply has to press the space bar.

When the user keeps the Shift key pressed, the block marking mode is used. This way, all nodes between the focus node and the initial node are marked, and all others are unmarked. The initial node is changed every time a node is marked without the Shift key being pressed. This happens when any movement is done without Shift or Control keys being pressed, or when the space bar is pressed together with Control.

Navigation

Using the keyboard:

In Motif when pressing Tab the focus goes to the next visible node, if there are no next visible node then the next control in the dialog receives the focus. In Windows and GTK the focus simply goes directly to the next control.

Using the left mouse button:

Removing a Node with "Del"

By default the Del key is not processed, but you can implement it using a simple K_ANY callback:

int k_any(Ihandle* ih, int c)
{
  if (c == K_DEL) 
   IupSetAttribute(ih,"DELNODE","MARKED");
  return IUP_CONTINUE;
}

Extra Functions

IupTree has functions that allow associating a pointer (or a user defined id) to a node. In order to do that, you provide the id of the node and the pointer (userid); even if the node's id changes later on, the userid will still be associated with the given node. In IupLua, instead of a pointer the same functions are defined for table and userdata. These functions use the USERDATAid attribute.


int IupTreeSetUserId(Ihandle *ih, int id, void *userid); [in C]
iup.TreeSetUserId(ih: ihandle, id: number, userid: userdata/table) [in Lua]

ih: Identifier of the interface element.
id: Node identifier.
userid: User pointer or Lua table to be associated with the node. Use NULL (nil) value to remove the association.

Returns a non zero value if the node was found.

Associates an userid with a given id. If the id of the node is changed, the userid remains the same.

Associations to Lua objects in Lua 5 are referenced in the Lua REGISTRY. So they can be retrieved later. This means also that the associated object will not be garbage collected until its reference is removed. Also, the user should not use the same table to reference different nodes (neither in the same nor across different trees.)

It is similar of setting the USERDATAid attribute, but with the additional feature of storing the Lua object in the registry.

void* IupTreeGetUserId(Ihandle *ih, int id); [in C] 
iup.TreeGetUserId(ih: ihandle, id: number) -> (ret: userdata/table) [in Lua]

ih: Identifier of the interface element.
id: Node identifier.

Returns the pointer or Lua table associated to the node or NULL if none was associated. SetUserId must have been called for the node with the given id.

It is similar of retrieving the USERDATAid attribute, but the Lua object is retrieved from the REGISTRY.

int IupTreeGetId(Ihandle *ih, void *userid); [in C] 
iup.TreeGetId(ih: ihandle, userid: userdata/table) -> (ret: number) [in Lua]

ih: Identifier of the interface element.
userid: Pointer or Lua table associated to the node.

Returns the id of the node that has the userid on success or -1 (nil) if not found. SetUserId must have been called with the same userid.


Here are some utilities exclusive for Lua.

iup.TreeAddNodes(ih: ihandle, tree: table, [id: number]) [in Lua]

ih: Identifier of the interface element.
tree: table of nodes.
id: optional existing node. The default is the first (0).

Initializes the tree using the given Lua table as values for the tree nodes using ADDBRANCH and ADDLEAF (so it also must be done after map). For example:

tree_nodes = 
{
  branchname = "Figures",
  "Other",
  {
    branchname = "triangle",
    state = "COLLAPSED",
    "equilateral",
    "isoceles",
    "scalenus",
  },
  {
    branchname = "parallelogram",
    "square",
    { leafname = "diamond", color = "92 92 255", titlefont = "Courier, 14" },
  },
  { branchname = "2D" },
  { branchname = "3D" },
}

tree = iup.tree{}
dlg = iup.dialog{tree}

dlg:map()

iup.TreeAddNodes(tree, tree_nodes)

dlg:show()

Inside a table branchname defines a branch and its title, leafname defines a leaf and its title. When a node inside a branch is not a table then it is a leaf and only defines the leaf title. When leafname or branchname are used you can also define other node attributes: color, state, titlefont, marked, image and imageexpanded; without specifying the node id. You can also use userid to associate an userdata or table just like in iup.TreeSetUserId. (since 3.0)

iup.TreeSetNodeAttributes(ih: ihandle, id: number, attrs: table) [in Lua]

ih: Identifier of the interface element.
id: existing node.
tree: table of attributes.

Sets a group of attributes stored in a table in the form attrs = {name = value, ...}.

iup.TreeSetAncestorsAttributes(ih: ihandle, id: number, attrs: table) [in Lua]

ih: Identifier of the interface element.
id: existing node.
tree: table of attributes.

Calls iup.TreeSetNodeAttributes for all ancestors of the given node (not including the node).

iup.TreeSetDescentsAttributes(ih: ihandle, id: number, attrs: table) [in Lua]

ih: Identifier of the interface element.
id: existing node.
tree: table of attributes.

Calls iup.TreeSetNodeAttributes for all descendents of the given node (not including the node).

Utility Functions

These functions can be used to set and get attributes from the element:

void  IupSetAttributeId(Ihandle *ih, const char* name, int id, const char* value);
char* IupGetAttributeId(Ihandle *ih, const char* name, int id);
int   IupGetIntId(Ihandle *ih, const char* name, int id);
float IupGetFloatId(Ihandle *ih, const char* name, int id);
void  IupSetfAttributeId(Ihandle *ih, const char* name, int id, const char* format, ...);
void  IupSetIntId(Ihandle* ih, const char* name, int id, int value);
void  IupSetFloatId(Ihandle* ih, const char* name, int id, float value);

They work just like the respective traditional set and get functions. But the attribute string is complemented with the id value. For ex:

IupSetAttributeId(ih, "KIND", 30, value) == IupSetAttribute(ih, "KIND30", value)
IupSetAttributeId(ih, "ADDLEAF", 10, value) == IupSetAttribute(ih, "ADDLEAF10", value)

But these functions are faster than the traditional functions because they do not need to parse the attribute name string and the application does not need to concatenate the attribute name with the id.


See also the IupTreeUtil contributed by Sergio Maffra and Frederico Abraham. It is an utility wrapper in C++ for the IupTree with some limitations.

Examples

Browse for Example Files

Windows
Motif
GTK